@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.
@@ -0,0 +1,173 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { renderHook, act } from '@testing-library/react';
3
+ import { useDebounce } from '../useDebounce';
4
+
5
+ describe('useDebounce', () => {
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
9
+
10
+ afterEach(() => {
11
+ vi.useRealTimers();
12
+ });
13
+
14
+ it('should return initial value immediately', () => {
15
+ const { result } = renderHook(() => useDebounce('initial', 300));
16
+ expect(result.current).toBe('initial');
17
+ });
18
+
19
+ it('should debounce value updates', () => {
20
+ const { result, rerender } = renderHook(
21
+ ({ value, delay }) => useDebounce(value, delay),
22
+ { initialProps: { value: 'initial', delay: 300 } }
23
+ );
24
+
25
+ expect(result.current).toBe('initial');
26
+
27
+ // Update value
28
+ rerender({ value: 'updated', delay: 300 });
29
+
30
+ // Value should still be initial before delay
31
+ expect(result.current).toBe('initial');
32
+
33
+ // Fast forward time by 300ms
34
+ act(() => {
35
+ vi.advanceTimersByTime(300);
36
+ });
37
+
38
+ // Value should now be updated
39
+ expect(result.current).toBe('updated');
40
+ });
41
+
42
+ it('should reset timer on rapid value changes', () => {
43
+ const { result, rerender } = renderHook(
44
+ ({ value, delay }) => useDebounce(value, delay),
45
+ { initialProps: { value: 'initial', delay: 300 } }
46
+ );
47
+
48
+ // First update
49
+ rerender({ value: 'first', delay: 300 });
50
+ act(() => {
51
+ vi.advanceTimersByTime(100);
52
+ });
53
+
54
+ // Second update before first delay completes
55
+ rerender({ value: 'second', delay: 300 });
56
+ act(() => {
57
+ vi.advanceTimersByTime(100);
58
+ });
59
+
60
+ // Third update before second delay completes
61
+ rerender({ value: 'third', delay: 300 });
62
+
63
+ // Value should still be initial
64
+ expect(result.current).toBe('initial');
65
+
66
+ // Complete the delay
67
+ act(() => {
68
+ vi.advanceTimersByTime(300);
69
+ });
70
+
71
+ // Should have the last value
72
+ expect(result.current).toBe('third');
73
+ });
74
+
75
+ it('should use default delay of 300ms', () => {
76
+ const { result, rerender } = renderHook(({ value }) => useDebounce(value), {
77
+ initialProps: { value: 'initial' },
78
+ });
79
+
80
+ rerender({ value: 'updated' });
81
+
82
+ act(() => {
83
+ vi.advanceTimersByTime(299);
84
+ });
85
+ expect(result.current).toBe('initial');
86
+
87
+ act(() => {
88
+ vi.advanceTimersByTime(1);
89
+ });
90
+ expect(result.current).toBe('updated');
91
+ });
92
+
93
+ it('should work with different value types', () => {
94
+ // Test with number
95
+ const { result: numberResult, rerender: numberRerender } = renderHook(
96
+ ({ value }) => useDebounce(value, 100),
97
+ { initialProps: { value: 0 } }
98
+ );
99
+
100
+ numberRerender({ value: 42 });
101
+ act(() => {
102
+ vi.advanceTimersByTime(100);
103
+ });
104
+ expect(numberResult.current).toBe(42);
105
+
106
+ // Test with object
107
+ const { result: objectResult, rerender: objectRerender } = renderHook(
108
+ ({ value }) => useDebounce(value, 100),
109
+ { initialProps: { value: { key: 'initial' } } }
110
+ );
111
+
112
+ objectRerender({ value: { key: 'updated' } });
113
+ act(() => {
114
+ vi.advanceTimersByTime(100);
115
+ });
116
+ expect(objectResult.current).toEqual({ key: 'updated' });
117
+
118
+ // Test with array
119
+ const { result: arrayResult, rerender: arrayRerender } = renderHook(
120
+ ({ value }) => useDebounce(value, 100),
121
+ { initialProps: { value: [1, 2, 3] } }
122
+ );
123
+
124
+ arrayRerender({ value: [4, 5, 6] });
125
+ act(() => {
126
+ vi.advanceTimersByTime(100);
127
+ });
128
+ expect(arrayResult.current).toEqual([4, 5, 6]);
129
+ });
130
+
131
+ it('should handle delay changes', () => {
132
+ const { result, rerender } = renderHook(
133
+ ({ value, delay }) => useDebounce(value, delay),
134
+ { initialProps: { value: 'initial', delay: 300 } }
135
+ );
136
+
137
+ rerender({ value: 'updated', delay: 300 });
138
+
139
+ // Change delay before first one completes
140
+ rerender({ value: 'updated', delay: 500 });
141
+
142
+ act(() => {
143
+ vi.advanceTimersByTime(300);
144
+ });
145
+
146
+ // Should still be initial because delay changed
147
+ expect(result.current).toBe('initial');
148
+
149
+ act(() => {
150
+ vi.advanceTimersByTime(200);
151
+ });
152
+
153
+ // Now should be updated
154
+ expect(result.current).toBe('updated');
155
+ });
156
+
157
+ it('should cleanup timer on unmount', () => {
158
+ const { unmount, rerender } = renderHook(
159
+ ({ value }) => useDebounce(value, 300),
160
+ { initialProps: { value: 'initial' } }
161
+ );
162
+
163
+ rerender({ value: 'updated' });
164
+
165
+ // Unmount before delay completes
166
+ unmount();
167
+
168
+ // Advance timers - should not cause errors
169
+ act(() => {
170
+ vi.advanceTimersByTime(300);
171
+ });
172
+ });
173
+ });
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cn } from '../cn';
3
+
4
+ describe('cn', () => {
5
+ it('should merge class names', () => {
6
+ expect(cn('foo', 'bar')).toBe('foo bar');
7
+ });
8
+
9
+ it('should handle conditional classes', () => {
10
+ const showBar = false;
11
+ const showBaz = true;
12
+ expect(cn('foo', showBar && 'bar', 'baz')).toBe('foo baz');
13
+ expect(cn('foo', showBaz && 'bar', 'baz')).toBe('foo bar baz');
14
+ });
15
+
16
+ it('should handle undefined and null values', () => {
17
+ expect(cn('foo', undefined, null, 'bar')).toBe('foo bar');
18
+ });
19
+
20
+ it('should handle arrays', () => {
21
+ expect(cn(['foo', 'bar'], 'baz')).toBe('foo bar baz');
22
+ });
23
+
24
+ it('should handle objects', () => {
25
+ expect(cn({ foo: true, bar: false, baz: true })).toBe('foo baz');
26
+ });
27
+
28
+ it('should merge Tailwind classes correctly', () => {
29
+ expect(cn('px-4 py-2', 'px-6')).toBe('py-2 px-6');
30
+ });
31
+
32
+ it('should handle empty inputs', () => {
33
+ expect(cn()).toBe('');
34
+ expect(cn('')).toBe('');
35
+ });
36
+
37
+ it('should merge conflicting Tailwind padding classes', () => {
38
+ expect(cn('p-4', 'p-6')).toBe('p-6');
39
+ expect(cn('px-4', 'px-6')).toBe('px-6');
40
+ expect(cn('py-2', 'py-4')).toBe('py-4');
41
+ });
42
+
43
+ it('should merge conflicting Tailwind margin classes', () => {
44
+ expect(cn('m-4', 'm-6')).toBe('m-6');
45
+ expect(cn('mx-4', 'mx-6')).toBe('mx-6');
46
+ });
47
+
48
+ it('should merge conflicting Tailwind text color classes', () => {
49
+ expect(cn('text-red-500', 'text-blue-500')).toBe('text-blue-500');
50
+ });
51
+
52
+ it('should merge conflicting Tailwind background classes', () => {
53
+ expect(cn('bg-red-500', 'bg-blue-500')).toBe('bg-blue-500');
54
+ });
55
+
56
+ it('should preserve non-conflicting classes', () => {
57
+ expect(cn('flex', 'items-center', 'justify-center')).toBe(
58
+ 'flex items-center justify-center'
59
+ );
60
+ });
61
+
62
+ it('should handle mixed Tailwind and custom classes', () => {
63
+ expect(cn('custom-class', 'p-4', 'another-class')).toBe(
64
+ 'custom-class p-4 another-class'
65
+ );
66
+ });
67
+ });
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ severityColors,
4
+ domainColors,
5
+ chartColors,
6
+ getDomainColor,
7
+ getSeverityColor,
8
+ hexToRgba,
9
+ } from '../colors';
10
+
11
+ describe('Color Utilities', () => {
12
+ describe('severityColors', () => {
13
+ it('should have correct severity color mappings', () => {
14
+ expect(severityColors.critical).toBe('#ef4444');
15
+ expect(severityColors.major).toBe('#f59e0b');
16
+ expect(severityColors.minor).toBe('#eab308');
17
+ expect(severityColors.info).toBe('#60a5fa');
18
+ });
19
+ });
20
+
21
+ describe('domainColors', () => {
22
+ it('should have at least 8 domain colors', () => {
23
+ expect(domainColors.length).toBeGreaterThanOrEqual(8);
24
+ });
25
+
26
+ it('should contain valid hex color codes', () => {
27
+ const hexPattern = /^#[0-9a-f]{6}$/i;
28
+ domainColors.forEach((color) => {
29
+ expect(color).toMatch(hexPattern);
30
+ });
31
+ });
32
+ });
33
+
34
+ describe('chartColors', () => {
35
+ it('should have correct chart color mappings', () => {
36
+ expect(chartColors.primary).toBe('#3b82f6');
37
+ expect(chartColors.success).toBe('#10b981');
38
+ expect(chartColors.warning).toBe('#f59e0b');
39
+ expect(chartColors.danger).toBe('#ef4444');
40
+ expect(chartColors.info).toBe('#06b6d4');
41
+ });
42
+ });
43
+
44
+ describe('getDomainColor', () => {
45
+ it('should return correct color for valid index', () => {
46
+ expect(getDomainColor(0)).toBe(domainColors[0]);
47
+ expect(getDomainColor(1)).toBe(domainColors[1]);
48
+ expect(getDomainColor(2)).toBe(domainColors[2]);
49
+ });
50
+
51
+ it('should wrap around for indices greater than array length', () => {
52
+ const length = domainColors.length;
53
+ expect(getDomainColor(length)).toBe(domainColors[0]);
54
+ expect(getDomainColor(length + 1)).toBe(domainColors[1]);
55
+ expect(getDomainColor(length * 2)).toBe(domainColors[0]);
56
+ });
57
+ });
58
+
59
+ describe('getSeverityColor', () => {
60
+ it('should return correct color for critical severity', () => {
61
+ expect(getSeverityColor('critical')).toBe('#ef4444');
62
+ });
63
+
64
+ it('should return correct color for major severity', () => {
65
+ expect(getSeverityColor('major')).toBe('#f59e0b');
66
+ });
67
+
68
+ it('should return correct color for minor severity', () => {
69
+ expect(getSeverityColor('minor')).toBe('#eab308');
70
+ });
71
+
72
+ it('should return correct color for info severity', () => {
73
+ expect(getSeverityColor('info')).toBe('#60a5fa');
74
+ });
75
+ });
76
+
77
+ describe('hexToRgba', () => {
78
+ it('should convert hex to rgba with alpha 1', () => {
79
+ expect(hexToRgba('#ff0000', 1)).toBe('rgba(255, 0, 0, 1)');
80
+ });
81
+
82
+ it('should convert hex to rgba with alpha 0.5', () => {
83
+ expect(hexToRgba('#00ff00', 0.5)).toBe('rgba(0, 255, 0, 0.5)');
84
+ });
85
+
86
+ it('should convert hex to rgba with alpha 0', () => {
87
+ expect(hexToRgba('#0000ff', 0)).toBe('rgba(0, 0, 255, 0)');
88
+ });
89
+
90
+ it('should handle mixed hex colors', () => {
91
+ expect(hexToRgba('#3b82f6', 0.8)).toBe('rgba(59, 130, 246, 0.8)');
92
+ });
93
+ });
94
+ });