@aiready/components 0.13.22 → 0.13.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/components/__tests__/card.test.tsx +31 -0
- package/src/components/__tests__/checkbox.test.tsx +75 -0
- package/src/components/__tests__/container.test.tsx +70 -0
- package/src/components/__tests__/grid.test.tsx +172 -0
- package/src/components/__tests__/input.test.tsx +46 -0
- package/src/components/__tests__/label.test.tsx +53 -0
- package/src/components/__tests__/modal.test.tsx +88 -0
- package/src/components/__tests__/radio-group.test.tsx +107 -0
- package/src/components/__tests__/select.test.tsx +100 -0
- package/src/components/__tests__/separator.test.tsx +72 -0
- package/src/components/__tests__/stack.test.tsx +197 -0
- package/src/components/__tests__/switch.test.tsx +85 -0
- package/src/components/__tests__/textarea.test.tsx +96 -0
- package/src/hooks/__tests__/useDebounce.test.ts +173 -0
- package/src/utils/__tests__/cn.test.ts +67 -0
- package/src/utils/__tests__/colors.test.ts +94 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/components",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.23",
|
|
4
4
|
"description": "Unified shared components library (UI, charts, hooks, utilities) for AIReady",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"framer-motion": "^12.35.0",
|
|
129
129
|
"lucide-react": "^0.577.0",
|
|
130
130
|
"tailwind-merge": "^3.0.0",
|
|
131
|
-
"@aiready/core": "0.23.
|
|
131
|
+
"@aiready/core": "0.23.24"
|
|
132
132
|
},
|
|
133
133
|
"devDependencies": {
|
|
134
134
|
"@testing-library/jest-dom": "^6.6.5",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Card } from '../card';
|
|
4
|
+
|
|
5
|
+
describe('Card', () => {
|
|
6
|
+
it('should render children content', () => {
|
|
7
|
+
render(<Card>Test Content</Card>);
|
|
8
|
+
expect(screen.getByText('Test Content')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should apply custom className', () => {
|
|
12
|
+
const { container } = render(<Card className="custom-class">Content</Card>);
|
|
13
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should render with default styles', () => {
|
|
17
|
+
const { container } = render(<Card>Content</Card>);
|
|
18
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should forward ref', () => {
|
|
22
|
+
const ref = { current: null };
|
|
23
|
+
render(<Card ref={ref}>Content</Card>);
|
|
24
|
+
expect(ref.current).not.toBeNull();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should spread additional props', () => {
|
|
28
|
+
const { container } = render(<Card data-testid="card">Content</Card>);
|
|
29
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'card');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { Checkbox } from '../checkbox';
|
|
4
|
+
|
|
5
|
+
describe('Checkbox', () => {
|
|
6
|
+
it('should render a checkbox input', () => {
|
|
7
|
+
render(<Checkbox />);
|
|
8
|
+
expect(screen.getByRole('checkbox')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should render with a label', () => {
|
|
12
|
+
render(<Checkbox label="Accept terms" />);
|
|
13
|
+
expect(screen.getByLabelText('Accept terms')).toBeInTheDocument();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should not render label when not provided', () => {
|
|
17
|
+
const { container } = render(<Checkbox />);
|
|
18
|
+
expect(container.querySelector('label')).not.toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should apply custom className', () => {
|
|
22
|
+
const { container } = render(<Checkbox className="custom-class" />);
|
|
23
|
+
expect(container.querySelector('input')).toHaveClass('custom-class');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle checked state', () => {
|
|
27
|
+
render(<Checkbox checked readOnly />);
|
|
28
|
+
expect(screen.getByRole('checkbox')).toBeChecked();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should handle unchecked state', () => {
|
|
32
|
+
render(<Checkbox checked={false} readOnly />);
|
|
33
|
+
expect(screen.getByRole('checkbox')).not.toBeChecked();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should call onChange when clicked', () => {
|
|
37
|
+
const handleChange = vi.fn();
|
|
38
|
+
render(<Checkbox onChange={handleChange} />);
|
|
39
|
+
fireEvent.click(screen.getByRole('checkbox'));
|
|
40
|
+
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should be disabled when disabled prop is set', () => {
|
|
44
|
+
render(<Checkbox disabled />);
|
|
45
|
+
expect(screen.getByRole('checkbox')).toBeDisabled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should forward ref', () => {
|
|
49
|
+
const ref = { current: null };
|
|
50
|
+
render(<Checkbox ref={ref} />);
|
|
51
|
+
expect(ref.current).not.toBeNull();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should spread additional props', () => {
|
|
55
|
+
const { container } = render(<Checkbox data-testid="checkbox" />);
|
|
56
|
+
expect(container.querySelector('input')).toHaveAttribute(
|
|
57
|
+
'data-testid',
|
|
58
|
+
'checkbox'
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should use provided id', () => {
|
|
63
|
+
render(<Checkbox id="custom-id" label="Test" />);
|
|
64
|
+
const checkbox = screen.getByRole('checkbox');
|
|
65
|
+
const label = screen.getByText('Test');
|
|
66
|
+
expect(checkbox).toHaveAttribute('id', 'custom-id');
|
|
67
|
+
expect(label).toHaveAttribute('for', 'custom-id');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should generate unique id when not provided', () => {
|
|
71
|
+
render(<Checkbox label="Test" />);
|
|
72
|
+
const checkbox = screen.getByRole('checkbox');
|
|
73
|
+
expect(checkbox).toHaveAttribute('id');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Container } from '../container';
|
|
4
|
+
|
|
5
|
+
describe('Container', () => {
|
|
6
|
+
it('should render children content', () => {
|
|
7
|
+
render(<Container>Test Content</Container>);
|
|
8
|
+
expect(screen.getByText('Test Content')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should apply custom className', () => {
|
|
12
|
+
const { container } = render(
|
|
13
|
+
<Container className="custom-class">Content</Container>
|
|
14
|
+
);
|
|
15
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should render with default lg size', () => {
|
|
19
|
+
const { container } = render(<Container>Content</Container>);
|
|
20
|
+
expect(container.firstChild).toHaveClass('max-w-screen-lg');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should render with sm size', () => {
|
|
24
|
+
const { container } = render(<Container size="sm">Content</Container>);
|
|
25
|
+
expect(container.firstChild).toHaveClass('max-w-screen-sm');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should render with md size', () => {
|
|
29
|
+
const { container } = render(<Container size="md">Content</Container>);
|
|
30
|
+
expect(container.firstChild).toHaveClass('max-w-screen-md');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should render with xl size', () => {
|
|
34
|
+
const { container } = render(<Container size="xl">Content</Container>);
|
|
35
|
+
expect(container.firstChild).toHaveClass('max-w-screen-xl');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should render with full size', () => {
|
|
39
|
+
const { container } = render(<Container size="full">Content</Container>);
|
|
40
|
+
expect(container.firstChild).toHaveClass('max-w-full');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should have responsive padding classes', () => {
|
|
44
|
+
const { container } = render(<Container>Content</Container>);
|
|
45
|
+
expect(container.firstChild).toHaveClass('px-4', 'sm:px-6', 'lg:px-8');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should be centered with mx-auto', () => {
|
|
49
|
+
const { container } = render(<Container>Content</Container>);
|
|
50
|
+
expect(container.firstChild).toHaveClass('mx-auto');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should have full width', () => {
|
|
54
|
+
const { container } = render(<Container>Content</Container>);
|
|
55
|
+
expect(container.firstChild).toHaveClass('w-full');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should forward ref', () => {
|
|
59
|
+
const ref = { current: null };
|
|
60
|
+
render(<Container ref={ref}>Content</Container>);
|
|
61
|
+
expect(ref.current).not.toBeNull();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should spread additional props', () => {
|
|
65
|
+
const { container } = render(
|
|
66
|
+
<Container data-testid="container">Content</Container>
|
|
67
|
+
);
|
|
68
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'container');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Grid } from '../grid';
|
|
4
|
+
|
|
5
|
+
describe('Grid', () => {
|
|
6
|
+
it('should render children content', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Grid>
|
|
9
|
+
<div>Item 1</div>
|
|
10
|
+
<div>Item 2</div>
|
|
11
|
+
</Grid>
|
|
12
|
+
);
|
|
13
|
+
expect(screen.getByText('Item 1')).toBeInTheDocument();
|
|
14
|
+
expect(screen.getByText('Item 2')).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should apply custom className', () => {
|
|
18
|
+
const { container } = render(
|
|
19
|
+
<Grid className="custom-class">
|
|
20
|
+
<div>Content</div>
|
|
21
|
+
</Grid>
|
|
22
|
+
);
|
|
23
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should render with default 3 columns', () => {
|
|
27
|
+
const { container } = render(
|
|
28
|
+
<Grid>
|
|
29
|
+
<div>Content</div>
|
|
30
|
+
</Grid>
|
|
31
|
+
);
|
|
32
|
+
expect(container.firstChild).toHaveClass(
|
|
33
|
+
'grid-cols-1',
|
|
34
|
+
'sm:grid-cols-2',
|
|
35
|
+
'lg:grid-cols-3'
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should render with 1 column', () => {
|
|
40
|
+
const { container } = render(
|
|
41
|
+
<Grid cols={1}>
|
|
42
|
+
<div>Content</div>
|
|
43
|
+
</Grid>
|
|
44
|
+
);
|
|
45
|
+
expect(container.firstChild).toHaveClass('grid-cols-1');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should render with 2 columns', () => {
|
|
49
|
+
const { container } = render(
|
|
50
|
+
<Grid cols={2}>
|
|
51
|
+
<div>Content</div>
|
|
52
|
+
</Grid>
|
|
53
|
+
);
|
|
54
|
+
expect(container.firstChild).toHaveClass('grid-cols-1', 'sm:grid-cols-2');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should render with 4 columns', () => {
|
|
58
|
+
const { container } = render(
|
|
59
|
+
<Grid cols={4}>
|
|
60
|
+
<div>Content</div>
|
|
61
|
+
</Grid>
|
|
62
|
+
);
|
|
63
|
+
expect(container.firstChild).toHaveClass(
|
|
64
|
+
'grid-cols-1',
|
|
65
|
+
'sm:grid-cols-2',
|
|
66
|
+
'lg:grid-cols-4'
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should render with 5 columns', () => {
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<Grid cols={5}>
|
|
73
|
+
<div>Content</div>
|
|
74
|
+
</Grid>
|
|
75
|
+
);
|
|
76
|
+
expect(container.firstChild).toHaveClass(
|
|
77
|
+
'grid-cols-1',
|
|
78
|
+
'sm:grid-cols-2',
|
|
79
|
+
'lg:grid-cols-5'
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should render with 6 columns', () => {
|
|
84
|
+
const { container } = render(
|
|
85
|
+
<Grid cols={6}>
|
|
86
|
+
<div>Content</div>
|
|
87
|
+
</Grid>
|
|
88
|
+
);
|
|
89
|
+
expect(container.firstChild).toHaveClass(
|
|
90
|
+
'grid-cols-1',
|
|
91
|
+
'sm:grid-cols-2',
|
|
92
|
+
'lg:grid-cols-6'
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should render with 12 columns', () => {
|
|
97
|
+
const { container } = render(
|
|
98
|
+
<Grid cols={12}>
|
|
99
|
+
<div>Content</div>
|
|
100
|
+
</Grid>
|
|
101
|
+
);
|
|
102
|
+
expect(container.firstChild).toHaveClass(
|
|
103
|
+
'grid-cols-1',
|
|
104
|
+
'sm:grid-cols-2',
|
|
105
|
+
'lg:grid-cols-12'
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should render with default md gap', () => {
|
|
110
|
+
const { container } = render(
|
|
111
|
+
<Grid>
|
|
112
|
+
<div>Content</div>
|
|
113
|
+
</Grid>
|
|
114
|
+
);
|
|
115
|
+
expect(container.firstChild).toHaveClass('gap-4');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should render with sm gap', () => {
|
|
119
|
+
const { container } = render(
|
|
120
|
+
<Grid gap="sm">
|
|
121
|
+
<div>Content</div>
|
|
122
|
+
</Grid>
|
|
123
|
+
);
|
|
124
|
+
expect(container.firstChild).toHaveClass('gap-2');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should render with lg gap', () => {
|
|
128
|
+
const { container } = render(
|
|
129
|
+
<Grid gap="lg">
|
|
130
|
+
<div>Content</div>
|
|
131
|
+
</Grid>
|
|
132
|
+
);
|
|
133
|
+
expect(container.firstChild).toHaveClass('gap-6');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should render with xl gap', () => {
|
|
137
|
+
const { container } = render(
|
|
138
|
+
<Grid gap="xl">
|
|
139
|
+
<div>Content</div>
|
|
140
|
+
</Grid>
|
|
141
|
+
);
|
|
142
|
+
expect(container.firstChild).toHaveClass('gap-8');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should have grid class', () => {
|
|
146
|
+
const { container } = render(
|
|
147
|
+
<Grid>
|
|
148
|
+
<div>Content</div>
|
|
149
|
+
</Grid>
|
|
150
|
+
);
|
|
151
|
+
expect(container.firstChild).toHaveClass('grid');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should forward ref', () => {
|
|
155
|
+
const ref = { current: null };
|
|
156
|
+
render(
|
|
157
|
+
<Grid ref={ref}>
|
|
158
|
+
<div>Content</div>
|
|
159
|
+
</Grid>
|
|
160
|
+
);
|
|
161
|
+
expect(ref.current).not.toBeNull();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should spread additional props', () => {
|
|
165
|
+
const { container } = render(
|
|
166
|
+
<Grid data-testid="grid">
|
|
167
|
+
<div>Content</div>
|
|
168
|
+
</Grid>
|
|
169
|
+
);
|
|
170
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'grid');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Input } from '../input';
|
|
4
|
+
|
|
5
|
+
describe('Input', () => {
|
|
6
|
+
it('should render an input element', () => {
|
|
7
|
+
render(<Input />);
|
|
8
|
+
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should apply custom className', () => {
|
|
12
|
+
const { container } = render(<Input className="custom-class" />);
|
|
13
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should handle placeholder text', () => {
|
|
17
|
+
render(<Input placeholder="Enter text" />);
|
|
18
|
+
expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle different input types', () => {
|
|
22
|
+
const { container } = render(<Input type="password" />);
|
|
23
|
+
expect(container.firstChild).toHaveAttribute('type', 'password');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should forward ref', () => {
|
|
27
|
+
const ref = { current: null };
|
|
28
|
+
render(<Input ref={ref} />);
|
|
29
|
+
expect(ref.current).not.toBeNull();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should be disabled when disabled prop is set', () => {
|
|
33
|
+
render(<Input disabled />);
|
|
34
|
+
expect(screen.getByRole('textbox')).toBeDisabled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle value prop', () => {
|
|
38
|
+
render(<Input value="test value" readOnly />);
|
|
39
|
+
expect(screen.getByRole('textbox')).toHaveValue('test value');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should spread additional props', () => {
|
|
43
|
+
const { container } = render(<Input data-testid="input" />);
|
|
44
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'input');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Label } from '../label';
|
|
4
|
+
|
|
5
|
+
describe('Label', () => {
|
|
6
|
+
it('should render children content', () => {
|
|
7
|
+
render(<Label>Test Label</Label>);
|
|
8
|
+
expect(screen.getByText('Test Label')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should apply custom className', () => {
|
|
12
|
+
const { container } = render(<Label className="custom-class">Label</Label>);
|
|
13
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should render with default styles', () => {
|
|
17
|
+
const { container } = render(<Label>Label</Label>);
|
|
18
|
+
expect(container.firstChild).toHaveClass(
|
|
19
|
+
'text-sm',
|
|
20
|
+
'font-medium',
|
|
21
|
+
'leading-none'
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should forward ref', () => {
|
|
26
|
+
const ref = { current: null };
|
|
27
|
+
render(<Label ref={ref}>Label</Label>);
|
|
28
|
+
expect(ref.current).not.toBeNull();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should spread additional props', () => {
|
|
32
|
+
const { container } = render(<Label data-testid="label">Label</Label>);
|
|
33
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'label');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should render as a label element', () => {
|
|
37
|
+
render(<Label>Label</Label>);
|
|
38
|
+
expect(screen.getByText('Label').tagName).toBe('LABEL');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should support htmlFor attribute', () => {
|
|
42
|
+
render(<Label htmlFor="input-id">Label</Label>);
|
|
43
|
+
expect(screen.getByText('Label')).toHaveAttribute('for', 'input-id');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should have peer-disabled classes', () => {
|
|
47
|
+
const { container } = render(<Label>Label</Label>);
|
|
48
|
+
expect(container.firstChild).toHaveClass(
|
|
49
|
+
'peer-disabled:cursor-not-allowed',
|
|
50
|
+
'peer-disabled:opacity-70'
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { Modal } from '../modal';
|
|
4
|
+
|
|
5
|
+
describe('Modal', () => {
|
|
6
|
+
const defaultProps = {
|
|
7
|
+
isOpen: true,
|
|
8
|
+
onClose: vi.fn(),
|
|
9
|
+
children: <div>Modal Content</div>,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should render children when open', () => {
|
|
17
|
+
render(<Modal {...defaultProps} />);
|
|
18
|
+
expect(screen.getByText('Modal Content')).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should not render children when closed', () => {
|
|
22
|
+
render(<Modal {...defaultProps} isOpen={false} />);
|
|
23
|
+
expect(screen.queryByText('Modal Content')).not.toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should render close button by default', () => {
|
|
27
|
+
render(<Modal {...defaultProps} />);
|
|
28
|
+
expect(screen.getByLabelText('Close modal')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should hide close button when showClose is false', () => {
|
|
32
|
+
render(<Modal {...defaultProps} showClose={false} />);
|
|
33
|
+
expect(screen.queryByLabelText('Close modal')).not.toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should call onClose when close button is clicked', () => {
|
|
37
|
+
render(<Modal {...defaultProps} />);
|
|
38
|
+
fireEvent.click(screen.getByLabelText('Close modal'));
|
|
39
|
+
expect(defaultProps.onClose).toHaveBeenCalledTimes(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should call onClose when backdrop is clicked', () => {
|
|
43
|
+
const { container } = render(<Modal {...defaultProps} />);
|
|
44
|
+
const backdrop = container.querySelector('.bg-slate-950\\/60');
|
|
45
|
+
if (backdrop) {
|
|
46
|
+
fireEvent.click(backdrop);
|
|
47
|
+
expect(defaultProps.onClose).toHaveBeenCalledTimes(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should apply custom maxWidth', () => {
|
|
52
|
+
const { container } = render(
|
|
53
|
+
<Modal {...defaultProps} maxWidth="max-w-2xl" />
|
|
54
|
+
);
|
|
55
|
+
const modalContent = container.querySelector('.max-w-2xl');
|
|
56
|
+
expect(modalContent).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should apply default maxWidth of max-w-4xl', () => {
|
|
60
|
+
const { container } = render(<Modal {...defaultProps} />);
|
|
61
|
+
const modalContent = container.querySelector('.max-w-4xl');
|
|
62
|
+
expect(modalContent).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should apply glass variant styles by default', () => {
|
|
66
|
+
const { container } = render(<Modal {...defaultProps} />);
|
|
67
|
+
const modalContent = container.querySelector('.bg-slate-900\\/90');
|
|
68
|
+
expect(modalContent).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should apply default variant styles', () => {
|
|
72
|
+
const { container } = render(<Modal {...defaultProps} variant="default" />);
|
|
73
|
+
const modalContent = container.querySelector('.bg-white');
|
|
74
|
+
expect(modalContent).toBeInTheDocument();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should have fixed positioning for backdrop', () => {
|
|
78
|
+
const { container } = render(<Modal {...defaultProps} />);
|
|
79
|
+
const wrapper = container.querySelector('.fixed.inset-0');
|
|
80
|
+
expect(wrapper).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should have z-index of 100', () => {
|
|
84
|
+
const { container } = render(<Modal {...defaultProps} />);
|
|
85
|
+
const wrapper = container.querySelector('.z-\\[100\\]');
|
|
86
|
+
expect(wrapper).toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { RadioGroup } from '../radio-group';
|
|
4
|
+
|
|
5
|
+
describe('RadioGroup', () => {
|
|
6
|
+
const options = [
|
|
7
|
+
{ value: 'option1', label: 'Option 1' },
|
|
8
|
+
{ value: 'option2', label: 'Option 2' },
|
|
9
|
+
{ value: 'option3', label: 'Option 3' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
name: 'test-radio',
|
|
14
|
+
options,
|
|
15
|
+
value: 'option1',
|
|
16
|
+
onChange: vi.fn(),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should render all radio options', () => {
|
|
24
|
+
render(<RadioGroup {...defaultProps} />);
|
|
25
|
+
expect(screen.getByLabelText('Option 1')).toBeInTheDocument();
|
|
26
|
+
expect(screen.getByLabelText('Option 2')).toBeInTheDocument();
|
|
27
|
+
expect(screen.getByLabelText('Option 3')).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should apply custom className', () => {
|
|
31
|
+
const { container } = render(
|
|
32
|
+
<RadioGroup {...defaultProps} className="custom-class" />
|
|
33
|
+
);
|
|
34
|
+
expect(container.firstChild).toHaveClass('custom-class');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should check the correct option', () => {
|
|
38
|
+
render(<RadioGroup {...defaultProps} />);
|
|
39
|
+
expect(screen.getByLabelText('Option 1')).toBeChecked();
|
|
40
|
+
expect(screen.getByLabelText('Option 2')).not.toBeChecked();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should call onChange when option is selected', () => {
|
|
44
|
+
render(<RadioGroup {...defaultProps} />);
|
|
45
|
+
fireEvent.click(screen.getByLabelText('Option 2'));
|
|
46
|
+
expect(defaultProps.onChange).toHaveBeenCalledWith('option2');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should render with vertical orientation by default', () => {
|
|
50
|
+
const { container } = render(<RadioGroup {...defaultProps} />);
|
|
51
|
+
expect(container.firstChild).toHaveClass('flex-col', 'gap-2');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should render with horizontal orientation', () => {
|
|
55
|
+
const { container } = render(
|
|
56
|
+
<RadioGroup {...defaultProps} orientation="horizontal" />
|
|
57
|
+
);
|
|
58
|
+
expect(container.firstChild).toHaveClass('flex-row', 'gap-4');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should disable specific options', () => {
|
|
62
|
+
const optionsWithDisabled = [
|
|
63
|
+
{ value: 'option1', label: 'Option 1' },
|
|
64
|
+
{ value: 'option2', label: 'Option 2', disabled: true },
|
|
65
|
+
];
|
|
66
|
+
render(<RadioGroup {...defaultProps} options={optionsWithDisabled} />);
|
|
67
|
+
expect(screen.getByLabelText('Option 2')).toBeDisabled();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should use the correct name for all radios', () => {
|
|
71
|
+
render(<RadioGroup {...defaultProps} />);
|
|
72
|
+
const radios = screen.getAllByRole('radio');
|
|
73
|
+
radios.forEach((radio) => {
|
|
74
|
+
expect(radio).toHaveAttribute('name', 'test-radio');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should generate unique ids for each option', () => {
|
|
79
|
+
render(<RadioGroup {...defaultProps} />);
|
|
80
|
+
expect(screen.getByLabelText('Option 1')).toHaveAttribute(
|
|
81
|
+
'id',
|
|
82
|
+
'test-radio-option1'
|
|
83
|
+
);
|
|
84
|
+
expect(screen.getByLabelText('Option 2')).toHaveAttribute(
|
|
85
|
+
'id',
|
|
86
|
+
'test-radio-option2'
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should forward ref', () => {
|
|
91
|
+
const ref = { current: null };
|
|
92
|
+
render(<RadioGroup {...defaultProps} ref={ref} />);
|
|
93
|
+
expect(ref.current).not.toBeNull();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should spread additional props', () => {
|
|
97
|
+
const { container } = render(
|
|
98
|
+
<RadioGroup {...defaultProps} data-testid="radio-group" />
|
|
99
|
+
);
|
|
100
|
+
expect(container.firstChild).toHaveAttribute('data-testid', 'radio-group');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should have flex class', () => {
|
|
104
|
+
const { container } = render(<RadioGroup {...defaultProps} />);
|
|
105
|
+
expect(container.firstChild).toHaveClass('flex');
|
|
106
|
+
});
|
|
107
|
+
});
|