Skip to content

Commit 88ffb50

Browse files
authored
Merge pull request #210 from olaservo/add-ui-tests
Add preliminary UI tests
2 parents c031831 + 25f5bb7 commit 88ffb50

File tree

8 files changed

+753
-7
lines changed

8 files changed

+753
-7
lines changed

client/jest.config.cjs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@ module.exports = {
33
testEnvironment: "jsdom",
44
moduleNameMapper: {
55
"^@/(.*)$": "<rootDir>/src/$1",
6-
"^../components/DynamicJsonForm$":
7-
"<rootDir>/src/utils/__mocks__/DynamicJsonForm.ts",
8-
"^../../components/DynamicJsonForm$":
9-
"<rootDir>/src/utils/__mocks__/DynamicJsonForm.ts",
6+
"\\.css$": "<rootDir>/src/__mocks__/styleMock.js",
107
},
118
transform: {
129
"^.+\\.tsx?$": [
1310
"ts-jest",
1411
{
15-
useESM: true,
1612
jsx: "react-jsx",
1713
tsconfig: "tsconfig.jest.json",
1814
},

client/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
},
2525
"dependencies": {
2626
"@modelcontextprotocol/sdk": "^1.6.1",
27-
"@radix-ui/react-dialog": "^1.1.3",
2827
"@radix-ui/react-checkbox": "^1.1.4",
28+
"@radix-ui/react-dialog": "^1.1.3",
2929
"@radix-ui/react-icons": "^1.3.0",
3030
"@radix-ui/react-label": "^2.1.0",
3131
"@radix-ui/react-popover": "^1.1.3",
@@ -50,6 +50,8 @@
5050
},
5151
"devDependencies": {
5252
"@eslint/js": "^9.11.1",
53+
"@testing-library/jest-dom": "^6.6.3",
54+
"@testing-library/react": "^16.2.0",
5355
"@types/jest": "^29.5.14",
5456
"@types/node": "^22.7.5",
5557
"@types/react": "^18.3.10",

client/src/__mocks__/styleMock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {};
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { render, screen, fireEvent } from "@testing-library/react";
2+
import { describe, it, expect, jest } from "@jest/globals";
3+
import DynamicJsonForm from "../DynamicJsonForm";
4+
import type { JsonSchemaType } from "../DynamicJsonForm";
5+
6+
describe("DynamicJsonForm String Fields", () => {
7+
const renderForm = (props = {}) => {
8+
const defaultProps = {
9+
schema: {
10+
type: "string" as const,
11+
description: "Test string field",
12+
} satisfies JsonSchemaType,
13+
value: undefined,
14+
onChange: jest.fn(),
15+
};
16+
return render(<DynamicJsonForm {...defaultProps} {...props} />);
17+
};
18+
19+
describe("Type Validation", () => {
20+
it("should handle numeric input as string type", () => {
21+
const onChange = jest.fn();
22+
renderForm({ onChange });
23+
24+
const input = screen.getByRole("textbox");
25+
fireEvent.change(input, { target: { value: "123321" } });
26+
27+
expect(onChange).toHaveBeenCalledWith("123321");
28+
// Verify the value is a string, not a number
29+
expect(typeof onChange.mock.calls[0][0]).toBe("string");
30+
});
31+
32+
it("should render as text input, not number input", () => {
33+
renderForm();
34+
const input = screen.getByRole("textbox");
35+
expect(input).toHaveProperty("type", "text");
36+
});
37+
});
38+
});
39+
40+
describe("DynamicJsonForm Integer Fields", () => {
41+
const renderForm = (props = {}) => {
42+
const defaultProps = {
43+
schema: {
44+
type: "integer" as const,
45+
description: "Test integer field",
46+
} satisfies JsonSchemaType,
47+
value: undefined,
48+
onChange: jest.fn(),
49+
};
50+
return render(<DynamicJsonForm {...defaultProps} {...props} />);
51+
};
52+
53+
describe("Basic Operations", () => {
54+
it("should render number input with step=1", () => {
55+
renderForm();
56+
const input = screen.getByRole("spinbutton");
57+
expect(input).toHaveProperty("type", "number");
58+
expect(input).toHaveProperty("step", "1");
59+
});
60+
61+
it("should pass integer values to onChange", () => {
62+
const onChange = jest.fn();
63+
renderForm({ onChange });
64+
65+
const input = screen.getByRole("spinbutton");
66+
fireEvent.change(input, { target: { value: "42" } });
67+
68+
expect(onChange).toHaveBeenCalledWith(42);
69+
// Verify the value is a number, not a string
70+
expect(typeof onChange.mock.calls[0][0]).toBe("number");
71+
});
72+
73+
it("should not pass string values to onChange", () => {
74+
const onChange = jest.fn();
75+
renderForm({ onChange });
76+
77+
const input = screen.getByRole("spinbutton");
78+
fireEvent.change(input, { target: { value: "abc" } });
79+
80+
expect(onChange).not.toHaveBeenCalled();
81+
});
82+
});
83+
84+
describe("Edge Cases", () => {
85+
it("should handle non-numeric input by not calling onChange", () => {
86+
const onChange = jest.fn();
87+
renderForm({ onChange });
88+
89+
const input = screen.getByRole("spinbutton");
90+
fireEvent.change(input, { target: { value: "abc" } });
91+
92+
expect(onChange).not.toHaveBeenCalled();
93+
});
94+
});
95+
});

0 commit comments

Comments
 (0)