Skip to content

Commit f6290cd

Browse files
committed
added test
1 parent 0b38705 commit f6290cd

File tree

12 files changed

+2218
-115
lines changed

12 files changed

+2218
-115
lines changed

ui/package-lock.json

Lines changed: 2073 additions & 69 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"lint": "eslint .",
10+
"test": "vitest",
1011
"preview": "vite preview"
1112
},
1213
"dependencies": {
@@ -22,6 +23,9 @@
2223
},
2324
"devDependencies": {
2425
"@eslint/js": "^9.15.0",
26+
"@testing-library/jest-dom": "^6.6.3",
27+
"@testing-library/react": "^16.1.0",
28+
"@testing-library/user-event": "^14.5.2",
2529
"@types/luxon": "^3.4.2",
2630
"@types/node": "^22.10.2",
2731
"@types/react": "^19.0.2",
@@ -32,8 +36,10 @@
3236
"eslint-plugin-react-hooks": "^5.1.0",
3337
"eslint-plugin-react-refresh": "^0.4.16",
3438
"globals": "^15.14.0",
39+
"jsdom": "^25.0.1",
3540
"typescript": "~5.7.2",
3641
"typescript-eslint": "^8.18.1",
37-
"vite": "^6.0.5"
42+
"vite": "^6.0.5",
43+
"vitest": "^2.1.8"
3844
}
3945
}

ui/pom.xml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
<configuration>
4141
<filesets>
4242
<fileset>
43-
<directory>node_modules</directory>
43+
<directory>${project.basedir}/node_modules</directory>
4444
</fileset>
4545
<fileset>
46-
<directory>dist</directory>
46+
<directory>${project.basedir}/dist</directory>
4747
</fileset>
4848
</filesets>
4949
</configuration>
@@ -82,6 +82,23 @@
8282
</arguments>
8383
</configuration>
8484
</execution>
85+
86+
<execution>
87+
<id>npm test</id>
88+
<goals>
89+
<goal>exec</goal>
90+
</goals>
91+
<phase>test</phase>
92+
<configuration>
93+
<executable>npm</executable>
94+
<arguments>
95+
<argument>run</argument>
96+
<argument>test</argument>
97+
<argument>--</argument>
98+
<argument>--run</argument>
99+
</arguments>
100+
</configuration>
101+
</execution>
85102
</executions>
86103
</plugin>
87104
</plugins>

ui/src/history/history.page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ const HistoryPage = () => {
3333
<PageView
3434
onPage={(p) => setPage(p)}
3535
data={triggers.data}
36-
className="mt-2 mb-2"
3736
/>
3837
</Col>
3938
<Col>

ui/src/shared/view/page.view.tsx

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,48 @@
11
import { PagedModel } from "@src/server-api";
2-
import { Form, Pagination } from "react-bootstrap";
2+
import React from "react";
3+
import { Pagination } from "react-bootstrap";
34

4-
const PageView = ({
5-
data,
6-
className,
7-
onPage,
8-
}: {
9-
className: string;
5+
interface PageViewProps {
106
data?: PagedModel<unknown>;
11-
onPage(page: number): void;
12-
}) => {
13-
if (!data || !data.content)
14-
return (
15-
<Pagination className={className}>
16-
<Pagination.Prev disabled />
17-
<Form.Label className="mt-2 ms-2 me-1">-</Form.Label>
18-
<Pagination.Next disabled />
19-
</Pagination>
20-
);
7+
onPage: (page: number) => void;
8+
}
9+
10+
const PageView: React.FC<PageViewProps> = ({ data, onPage }) => {
11+
const isDataAvailable = !!data && !!data.content;
12+
const currentPage = data?.page.number ?? 0;
13+
const totalPages = data?.page.totalPages ?? 0;
14+
const totalElements = data?.page.totalElements ?? 0;
15+
const pageSize = data?.page.size ?? 0;
16+
const contentLength = data?.content?.length ?? 0;
17+
18+
const handlePrevClick = () => {
19+
if (currentPage > 0) {
20+
onPage(currentPage - 1);
21+
}
22+
};
23+
24+
const handleNextClick = () => {
25+
if (currentPage < totalPages - 1) {
26+
onPage(currentPage + 1);
27+
}
28+
};
29+
30+
const displayCount = isDataAvailable
31+
? `${contentLength + pageSize * currentPage} / ${totalElements}`
32+
: "-";
33+
2134
return (
22-
<Pagination className="mt-2 mb-2">
35+
<Pagination className="mb-0 mt-0 align-items-center">
2336
<Pagination.Prev
24-
onClick={() => onPage(data.page.number - 1)}
25-
disabled={data.page.number === 0}
37+
data-testid="prev"
38+
onClick={handlePrevClick}
39+
disabled={!isDataAvailable || currentPage === 0}
2640
/>
27-
<Form.Label className="mt-2 ms-2 me-1">
28-
{data.content.length +
29-
data.page.size * data.page.number +
30-
" / " +
31-
data.page.totalElements}
32-
</Form.Label>
41+
<strong className="ms-2 me-2">{displayCount}</strong>
3342
<Pagination.Next
34-
onClick={() => onPage(data.page.number + 1)}
35-
disabled={data.page.number >= data.page.totalPages - 1}
43+
data-testid="next"
44+
onClick={handleNextClick}
45+
disabled={!isDataAvailable || currentPage >= totalPages - 1}
3646
/>
3747
</Pagination>
3848
);

ui/src/shared/view/trigger-list-item.view.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ const TriggerItemView = ({ trigger, afterCancel }: TriggerProps) => {
6161
</Container>
6262
</Accordion.Header>
6363
<Accordion.Body>
64-
{afterCancel && trigger.status === "WAITING" ? (
65-
<Row>
66-
<Col>
64+
{trigger.status === "WAITING" ? (
65+
<div className="d-flex gap-2 mb-2">
66+
<Button>Run now</Button>
67+
{afterCancel ? (
6768
<Button
6869
variant="danger"
6970
onClick={() => {
@@ -75,8 +76,8 @@ const TriggerItemView = ({ trigger, afterCancel }: TriggerProps) => {
7576
>
7677
Cancel Trigger
7778
</Button>
78-
</Col>
79-
</Row>
79+
) : undefined}
80+
</div>
8081
) : undefined}
8182
<Row>
8283
<Col>

ui/src/trigger/triggers.page.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,20 @@ const TriggersPage = () => {
1717
);
1818

1919
const doReload = () => {
20-
triggers.doGet("?size=5&page=" + page + "&taskId=" + selectedTask);
20+
triggers.doGet("?size=10&page=" + page + "&taskId=" + selectedTask);
2121
};
2222

2323
useAutoRefresh(10000, doReload, [page, selectedTask]);
2424

2525
return (
2626
<Stack gap={1}>
2727
<HttpErrorView error={triggers.error} />
28-
<Row className="align-items-center">
28+
<Row className="align-items-center mb-2">
2929
<Col>
3030
<TaskSelect onTaskChange={setSelectedTask} />
3131
</Col>
32-
<Col>
33-
<PageView
34-
onPage={(p) => setPage(p)}
35-
data={triggers.data}
36-
className="mt-2 mb-2"
37-
/>
32+
<Col className="align-items-center">
33+
<PageView onPage={(p) => setPage(p)} data={triggers.data} />
3834
</Col>
3935
<Col>
4036
<ReloadButton

ui/src/vite-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
/// <reference types="vitest" />
12
/// <reference types="vite/client" />

ui/test/setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@testing-library/jest-dom'
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { render, screen, fireEvent } from "@testing-library/react";
2+
import { describe, it, expect, vi, beforeEach } from "vitest";
3+
import PageView from "@src/shared/view/page.view";
4+
import { PagedModel } from "@src/server-api";
5+
6+
const mockOnPage = vi.fn();
7+
8+
const renderComponent = (data?: PagedModel<unknown>) =>
9+
render(<PageView data={data} onPage={mockOnPage} />);
10+
11+
describe("PageView Component", () => {
12+
beforeEach(() => {
13+
mockOnPage.mockClear();
14+
});
15+
16+
it("No data: should disable both buttons and display '-'", () => {
17+
renderComponent(undefined);
18+
19+
expect(screen.getByText("-")).toBeInTheDocument();
20+
expect(screen.getByTestId("next").closest("li")).toHaveClass(
21+
"disabled"
22+
);
23+
expect(screen.getByTestId("prev").closest("li")).toHaveClass(
24+
"disabled"
25+
);
26+
});
27+
28+
it("Middle page: should enable both Prev and Next", () => {
29+
renderComponent({
30+
page: { number: 1, size: 10, totalElements: 30, totalPages: 3 },
31+
content: new Array(10),
32+
});
33+
34+
expect(screen.getByText("20 / 30")).toBeInTheDocument();
35+
expect(
36+
screen.getByRole("button", { name: "Previous" })
37+
).not.toBeDisabled();
38+
expect(screen.getByRole("button", { name: "Next" })).not.toBeDisabled();
39+
40+
fireEvent.click(screen.getByRole("button", { name: "Previous" }));
41+
expect(mockOnPage).toHaveBeenCalledWith(0);
42+
43+
fireEvent.click(screen.getByRole("button", { name: "Next" }));
44+
expect(mockOnPage).toHaveBeenCalledWith(2);
45+
});
46+
47+
it("Empty page: should disable both buttons and show count as 0 / total", () => {
48+
renderComponent({
49+
page: { number: 0, size: 10, totalElements: 10, totalPages: 1 },
50+
content: [],
51+
});
52+
53+
expect(screen.getByText("0 / 10")).toBeInTheDocument();
54+
expect(screen.getByTestId("next").closest("li")).toHaveClass(
55+
"disabled"
56+
);
57+
expect(screen.getByTestId("prev").closest("li")).toHaveClass(
58+
"disabled"
59+
);
60+
});
61+
});

0 commit comments

Comments
 (0)