Skip to content

Commit eed73fa

Browse files
committed
test: add unit tests for remaining field widgets including AutoNumberField, FormulaField, SummaryField, PercentField, ImageField, LocationField, ObjectField, UserField, and VectorField
1 parent 7f2bb0d commit eed73fa

File tree

6 files changed

+180
-235
lines changed

6 files changed

+180
-235
lines changed

apps/console/src/__tests__/ObjectFormUnit.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class MockDataSource implements DataSource {
4444
}
4545

4646
async create(_objectName: string, data: any): Promise<any> {
47+
console.log('MockDataSource.create received:', data);
4748
return { ...data, id: 'new-id' };
4849
}
4950

packages/components/src/renderers/form/form.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ ComponentRegistry.register('form',
7777

7878
// Handle form submission
7979
const handleSubmit = form.handleSubmit(async (data) => {
80+
console.log('Form Renderer handleSubmit data:', data);
8081
setIsSubmitting(true);
8182
setSubmitError(null);
8283

@@ -87,7 +88,8 @@ ComponentRegistry.register('form',
8788
(data as any).nativeEvent ||
8889
typeof (data as any).preventDefault === 'function' ||
8990
typeof (data as any).stopPropagation === 'function' ||
90-
(data as any).target
91+
(data as any).target ||
92+
(data as any).bubbles
9193
);
9294

9395
if (isEvent) {
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
2+
import { render, screen, fireEvent } from '@testing-library/react';
3+
import { describe, it, expect, vi } from 'vitest';
4+
import { AutoNumberField } from './widgets/AutoNumberField';
5+
import { FormulaField } from './widgets/FormulaField';
6+
import { SummaryField } from './widgets/SummaryField';
7+
import { PercentField } from './widgets/PercentField';
8+
import { ImageField } from './widgets/ImageField';
9+
import { LocationField } from './widgets/LocationField';
10+
import { ObjectField } from './widgets/ObjectField';
11+
import { UserField } from './widgets/UserField';
12+
import { VectorField } from './widgets/VectorField';
13+
import type { FieldWidgetProps } from './widgets/types';
14+
15+
// ------------- Mocks & Setup -------------
16+
17+
const mockField = {
18+
name: 'test_field',
19+
label: 'Test Field',
20+
} as any;
21+
22+
const baseProps: FieldWidgetProps<any> = {
23+
field: mockField,
24+
value: undefined,
25+
onChange: vi.fn(),
26+
readonly: false,
27+
};
28+
29+
describe('Remaining Field Widgets', () => {
30+
31+
// 1. AutoNumberField
32+
describe('AutoNumberField', () => {
33+
it('should render value as string', () => {
34+
render(<AutoNumberField {...baseProps} value={1001} />);
35+
expect(screen.getByText('1001')).toBeInTheDocument();
36+
});
37+
38+
it('should render dash for null value', () => {
39+
render(<AutoNumberField {...baseProps} value={null as any} />);
40+
expect(screen.getByText('-')).toBeInTheDocument();
41+
});
42+
});
43+
44+
// 2. FormulaField
45+
describe('FormulaField', () => {
46+
it('should format return_type=currency', () => {
47+
const field = { ...mockField, return_type: 'currency' };
48+
render(<FormulaField {...baseProps} field={field} value={123.456} />);
49+
// Checks for 2 decimal places
50+
expect(screen.getByText('123.46')).toBeInTheDocument();
51+
});
52+
53+
it('should format return_type=boolean', () => {
54+
const field = { ...mockField, return_type: 'boolean' };
55+
render(<FormulaField {...baseProps} field={field} value={true} />);
56+
expect(screen.getByText('Yes')).toBeInTheDocument();
57+
});
58+
});
59+
60+
// 3. SummaryField
61+
describe('SummaryField', () => {
62+
it('should render count as integer', () => {
63+
const field = { ...mockField, summary_type: 'count' };
64+
render(<SummaryField {...baseProps} field={field} value={42} />);
65+
expect(screen.getByText('42')).toBeInTheDocument();
66+
});
67+
68+
it('should render sum with decimals', () => {
69+
const field = { ...mockField, summary_type: 'sum' };
70+
render(<SummaryField {...baseProps} field={field} value={10.566} />);
71+
expect(screen.getByText('10.57')).toBeInTheDocument();
72+
});
73+
});
74+
75+
// 4. PercentField
76+
describe('PercentField', () => {
77+
it('should display value * 100 in input', () => {
78+
render(<PercentField {...baseProps} value={0.5} />);
79+
const input = screen.getByRole('spinbutton') as HTMLInputElement;
80+
expect(input.value).toBe('50');
81+
});
82+
83+
it('should display formatted value in readonly', () => {
84+
render(<PercentField {...baseProps} value={0.125} readonly={true} />);
85+
expect(screen.getByText('12.50%')).toBeInTheDocument();
86+
});
87+
88+
it('should call onChange with value / 100', () => {
89+
const handleChange = vi.fn();
90+
render(<PercentField {...baseProps} onChange={handleChange} value={0} />);
91+
const input = screen.getByRole('spinbutton');
92+
fireEvent.change(input, { target: { value: '75' } });
93+
expect(handleChange).toHaveBeenCalledWith(0.75);
94+
});
95+
});
96+
97+
// 5. ImageField
98+
describe('ImageField', () => {
99+
const images = [
100+
{ url: 'http://example.com/1.jpg', name: 'Img 1' },
101+
{ url: 'http://example.com/2.jpg', name: 'Img 2' }
102+
];
103+
104+
it('should render images in readonly mode', () => {
105+
render(<ImageField {...baseProps} value={images} readonly={true} />);
106+
const imgs = screen.getAllByRole('img');
107+
expect(imgs).toHaveLength(2);
108+
expect(imgs[0]).toHaveAttribute('src', 'http://example.com/1.jpg');
109+
});
110+
111+
// Complex interaction omitted for brevity, focusing on render contracts
112+
});
113+
114+
// 6. LocationField
115+
describe('LocationField', () => {
116+
it('should render lat,long string', () => {
117+
const loc = { latitude: 34.05, longitude: -118.25 };
118+
render(<LocationField {...baseProps} value={loc} />);
119+
const input = screen.getByRole('textbox') as HTMLInputElement;
120+
expect(input.value).toContain('34.05, -118.25');
121+
});
122+
123+
it('should parse string input to object', () => {
124+
const handleChange = vi.fn();
125+
render(<LocationField {...baseProps} onChange={handleChange} />);
126+
const input = screen.getByRole('textbox');
127+
fireEvent.change(input, { target: { value: '10.5, 20.5' } });
128+
expect(handleChange).toHaveBeenCalledWith({ latitude: 10.5, longitude: 20.5 });
129+
});
130+
});
131+
132+
// 7. ObjectField
133+
describe('ObjectField', () => {
134+
const obj = { foo: 'bar', num: 1 };
135+
136+
it('should render JSON string in readonly', () => {
137+
render(<ObjectField {...baseProps} value={obj} readonly={true} />);
138+
// pre tag usually contains formatted JSON
139+
expect(screen.getByText(/"foo": "bar"/)).toBeInTheDocument();
140+
});
141+
142+
it('should parse valid JSON input', () => {
143+
const handleChange = vi.fn();
144+
render(<ObjectField {...baseProps} onChange={handleChange} value={obj} />);
145+
const textarea = screen.getByRole('textbox');
146+
const newJson = '{"test": true}';
147+
fireEvent.change(textarea, { target: { value: newJson } });
148+
expect(handleChange).toHaveBeenCalledWith({ test: true });
149+
});
150+
});
151+
152+
// 8. UserField
153+
describe('UserField', () => {
154+
const user = { name: 'Alice Smith', id: 'u1' };
155+
156+
it('should render user avatar in readonly', () => {
157+
render(<UserField {...baseProps} value={user} readonly={true} />);
158+
// Avatar fallback logic splits name
159+
expect(screen.getByText('AS')).toBeInTheDocument();
160+
});
161+
});
162+
163+
// 9. VectorField
164+
describe('VectorField', () => {
165+
it('should render vector values', () => {
166+
const vec = [0.12345, 0.67891, 0.00001];
167+
render(<VectorField {...baseProps} value={vec} />);
168+
expect(screen.getByText(/0.1235/)).toBeInTheDocument(); // toFixed(4)
169+
expect(screen.getByText('(3D)')).toBeInTheDocument();
170+
});
171+
});
172+
});

packages/plugin-form/src/ObjectForm.msw.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, it, expect, vi, beforeAll, afterAll, afterEach } from 'vitest';
22
import { render, screen, waitFor } from '@testing-library/react';
3+
import '@testing-library/jest-dom';
34
import { ObjectForm } from './ObjectForm';
45
import { ObjectStackAdapter } from '@object-ui/data-objectstack';
56
import { setupServer } from 'msw/node';

packages/plugin-grid/src/ObjectGrid.msw.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, it, expect, vi, beforeAll, afterAll, afterEach } from 'vitest';
22
import { render, screen, waitFor, within } from '@testing-library/react';
3+
import '@testing-library/jest-dom';
34
import { ObjectGrid } from './ObjectGrid';
45
import { ObjectStackAdapter } from '@object-ui/data-objectstack';
56
import { setupServer } from 'msw/node';

0 commit comments

Comments
 (0)