@tuturuuu/utils 0.0.2 → 0.6.0
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/CHANGELOG.md +305 -0
- package/biome.json +5 -0
- package/jsr.json +8 -8
- package/package.json +63 -32
- package/src/__tests__/ai-temp-auth.test.ts +309 -0
- package/src/__tests__/api-proxy-guard.test.ts +1451 -0
- package/src/__tests__/app-url.test.ts +270 -0
- package/src/__tests__/avatar-url.test.ts +97 -0
- package/src/__tests__/color-helper.test.ts +179 -0
- package/src/__tests__/constants.test.ts +351 -0
- package/src/__tests__/crypto.test.ts +107 -0
- package/src/__tests__/date-helper.test.ts +408 -0
- package/src/__tests__/fixtures/task-description-full-featured.json +456 -0
- package/src/__tests__/format.test.ts +317 -0
- package/src/__tests__/html-sanitizer.test.ts +360 -0
- package/src/__tests__/interest-calculator.test.ts +336 -0
- package/src/__tests__/interest-detector.test.ts +222 -0
- package/src/__tests__/label-colors.test.ts +241 -0
- package/src/__tests__/name-helper.test.ts +158 -0
- package/src/__tests__/node-diff.test.ts +576 -0
- package/src/__tests__/notification-service.test.ts +210 -0
- package/src/__tests__/onboarding-helper.test.ts +331 -0
- package/src/__tests__/path-helper.test.ts +152 -0
- package/src/__tests__/permissions.test.tsx +81 -0
- package/src/__tests__/request-emoji-limit.test.ts +172 -0
- package/src/__tests__/search-helper.test.ts +51 -0
- package/src/__tests__/storage-display-name.test.ts +37 -0
- package/src/__tests__/storage-path.test.ts +238 -0
- package/src/__tests__/tag-utils.test.ts +205 -0
- package/src/__tests__/task-description-yjs-state.test.ts +581 -0
- package/src/__tests__/task-helper-board-api-routing.test.ts +94 -0
- package/src/__tests__/task-helper-create-task.test.ts +129 -0
- package/src/__tests__/task-helpers.test.ts +464 -0
- package/src/__tests__/task-overrides.test.ts +305 -0
- package/src/__tests__/task-reorder-cache.test.ts +74 -0
- package/src/__tests__/task-sort-keys.test.ts +36 -0
- package/src/__tests__/task-transformers.test.ts +62 -0
- package/src/__tests__/text-helper.test.ts +776 -0
- package/src/__tests__/time-helper.test.ts +70 -0
- package/src/__tests__/time-tracker-period.test.ts +55 -0
- package/src/__tests__/timezone.test.ts +117 -0
- package/src/__tests__/upstash-rest.test.ts +77 -0
- package/src/__tests__/uuid-helper.test.ts +133 -0
- package/src/__tests__/workspace-helper.test.ts +859 -0
- package/src/__tests__/workspace-limits.test.ts +255 -0
- package/src/__tests__/yjs-helper.test.ts +581 -0
- package/src/abuse-protection/__tests__/backend-rate-limit.test.ts +113 -0
- package/src/abuse-protection/__tests__/edge.test.ts +136 -0
- package/src/abuse-protection/__tests__/index.test.ts +562 -0
- package/src/abuse-protection/__tests__/reputation.test.ts +192 -0
- package/src/abuse-protection/backend-rate-limit.ts +44 -0
- package/src/abuse-protection/constants.ts +117 -0
- package/src/abuse-protection/edge.ts +223 -0
- package/src/abuse-protection/index.ts +1545 -0
- package/src/abuse-protection/reputation.ts +587 -0
- package/src/abuse-protection/types.ts +97 -0
- package/src/abuse-protection/user-agent.ts +124 -0
- package/src/abuse-protection/user-suspension.ts +231 -0
- package/src/ai-temp-auth.ts +315 -0
- package/src/api-proxy-guard.ts +965 -0
- package/src/app-url.ts +96 -0
- package/src/avatar-url.ts +64 -0
- package/src/break-duration.ts +84 -0
- package/src/calendar-auth-token.test.ts +37 -0
- package/src/calendar-auth-token.ts +19 -0
- package/src/calendar-sync-coordination.md +197 -0
- package/src/calendar-utils.test.ts +169 -0
- package/src/calendar-utils.ts +91 -0
- package/src/color-helper.ts +110 -0
- package/src/common/nextjs.tsx +99 -0
- package/src/common/scan.tsx +15 -0
- package/src/configs/reports.ts +160 -0
- package/src/constants.ts +85 -0
- package/src/crypto.ts +21 -0
- package/src/currencies.ts +97 -0
- package/src/date-helper.ts +313 -0
- package/src/editor/convert-to-task.ts +264 -0
- package/src/editor/index.ts +5 -0
- package/src/email/__tests__/client.test.ts +141 -0
- package/src/email/__tests__/validation.test.ts +46 -0
- package/src/email/client.ts +92 -0
- package/src/email/server.ts +128 -0
- package/src/email/validation.ts +11 -0
- package/src/encryption/__tests__/calendar-events.test.ts +411 -0
- package/src/encryption/__tests__/configuration.test.ts +114 -0
- package/src/encryption/__tests__/field-encryption.test.ts +232 -0
- package/src/encryption/__tests__/key-generation.test.ts +30 -0
- package/src/encryption/__tests__/performance-edge-cases.test.ts +187 -0
- package/src/encryption/__tests__/test-helpers.ts +22 -0
- package/src/encryption/__tests__/workspace-key-encryption.test.ts +129 -0
- package/src/encryption/encryption-service.ts +343 -0
- package/src/encryption/index.ts +25 -0
- package/src/encryption/types.ts +57 -0
- package/src/exchange-rates.ts +49 -0
- package/src/feature-flags/__tests__/feature-flags.test.ts +302 -0
- package/src/feature-flags/core.ts +322 -0
- package/src/feature-flags/data.ts +16 -0
- package/src/feature-flags/default.ts +18 -0
- package/src/feature-flags/index.ts +7 -0
- package/src/feature-flags/requestable-features.ts +79 -0
- package/src/feature-flags/types.ts +4 -0
- package/src/fetcher.ts +2 -0
- package/src/finance/index.ts +4 -0
- package/src/finance/interest-calculator.ts +456 -0
- package/src/finance/interest-detector.ts +141 -0
- package/src/finance/transform-invoice-results.ts +219 -0
- package/src/finance/wallet-permissions.test.ts +169 -0
- package/src/finance/wallet-permissions.ts +82 -0
- package/src/format.ts +122 -3
- package/src/generated/platform-build-metadata.ts +11 -0
- package/src/hooks/use-platform.ts +64 -0
- package/src/html-sanitizer.ts +155 -0
- package/src/internal-domains.ts +497 -0
- package/src/keyboard-preset.ts +109 -0
- package/src/label-colors.ts +213 -0
- package/src/launchable-apps.test.ts +126 -0
- package/src/launchable-apps.ts +490 -0
- package/src/name-helper.ts +269 -0
- package/src/next-config.test.ts +234 -0
- package/src/next-config.ts +203 -0
- package/src/node-diff.ts +375 -0
- package/src/notification-service.ts +379 -0
- package/src/nova/scores/__tests__/calculate.test.ts +254 -0
- package/src/nova/scores/calculate.ts +132 -0
- package/src/nova/submissions/check-permission.ts +132 -0
- package/src/onboarding-helper.ts +213 -0
- package/src/path-helper.ts +93 -0
- package/src/permissions.tsx +1170 -0
- package/src/plan-helpers.test.ts +188 -0
- package/src/plan-helpers.ts +80 -0
- package/src/platform-release.test.ts +74 -0
- package/src/platform-release.ts +155 -0
- package/src/portless.ts +124 -0
- package/src/priority-styles.ts +42 -0
- package/src/request-emoji-limit.ts +335 -0
- package/src/search-helper.ts +18 -0
- package/src/search.test.ts +89 -0
- package/src/search.ts +355 -0
- package/src/storage-display-name.ts +30 -0
- package/src/storage-path.ts +147 -0
- package/src/tag-utils.ts +159 -0
- package/src/task/reorder.ts +245 -0
- package/src/task/transformers.ts +149 -0
- package/src/task-date-timezone.ts +133 -0
- package/src/task-description-content.ts +240 -0
- package/src/task-helper/board.ts +193 -0
- package/src/task-helper/bulk-actions.ts +564 -0
- package/src/task-helper/personal-external-staging.ts +21 -0
- package/src/task-helper/recycle-bin.ts +202 -0
- package/src/task-helper/relationships.ts +346 -0
- package/src/task-helper/shared.ts +109 -0
- package/src/task-helper/sort-keys.ts +337 -0
- package/src/task-helper/task-hooks-basic.ts +342 -0
- package/src/task-helper/task-hooks-move.ts +264 -0
- package/src/task-helper/task-operations.ts +278 -0
- package/src/task-helper.ts +12 -0
- package/src/task-helpers.ts +241 -0
- package/src/task-list-status.ts +62 -0
- package/src/task-overrides.ts +82 -0
- package/src/task-snapshot.ts +374 -0
- package/src/text-diff.ts +81 -0
- package/src/text-helper.ts +537 -0
- package/src/time-helper.ts +63 -0
- package/src/time-tracker-period.ts +73 -0
- package/src/timeblock-helper.ts +418 -0
- package/src/timezone.ts +190 -0
- package/src/timezones.json +1271 -0
- package/src/upstash-rest.ts +56 -0
- package/src/user-helper.ts +296 -0
- package/src/uuid-helper.ts +11 -0
- package/src/workspace-handle.ts +10 -0
- package/src/workspace-helper.ts +1408 -0
- package/src/workspace-limits.ts +68 -0
- package/src/yjs-helper.ts +217 -0
- package/src/yjs-task-description.ts +81 -0
- package/tsconfig.json +3 -5
- package/tsconfig.typecheck.json +33 -0
- package/vitest.config.ts +36 -0
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -2
- package/dist/index.mjs.map +0 -1
- package/eslint.config.mjs +0 -20
- package/rollup.config.js +0 -41
- package/src/index.ts +0 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Label Colors Utilities
|
|
3
|
+
*
|
|
4
|
+
* Tests the computeAccessibleLabelStyles function which computes
|
|
5
|
+
* accessible label styles with proper contrast based on color input.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { computeAccessibleLabelStyles } from '../label-colors';
|
|
10
|
+
|
|
11
|
+
describe('computeAccessibleLabelStyles', () => {
|
|
12
|
+
describe('Hex color inputs', () => {
|
|
13
|
+
it('should handle 6-character hex with # prefix', () => {
|
|
14
|
+
const result = computeAccessibleLabelStyles('#3b82f6');
|
|
15
|
+
expect(result).not.toBeNull();
|
|
16
|
+
expect(result?.bg).toMatch(/^#[0-9a-f]{6}[0-9a-f]{2}$/);
|
|
17
|
+
expect(result?.border).toMatch(/^#[0-9a-f]{6}[0-9a-f]{2}$/);
|
|
18
|
+
expect(result?.text).toMatch(/^#[0-9a-f]{6}$/);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle 6-character hex without # prefix', () => {
|
|
22
|
+
const result = computeAccessibleLabelStyles('3b82f6');
|
|
23
|
+
expect(result).not.toBeNull();
|
|
24
|
+
expect(result?.bg).toBe('#3b82f61a');
|
|
25
|
+
expect(result?.border).toBe('#3b82f64d');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle 3-character hex with # prefix', () => {
|
|
29
|
+
const result = computeAccessibleLabelStyles('#f00');
|
|
30
|
+
expect(result).not.toBeNull();
|
|
31
|
+
expect(result?.bg).toBe('#ff00001a');
|
|
32
|
+
expect(result?.border).toBe('#ff00004d');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should handle 3-character hex without # prefix', () => {
|
|
36
|
+
const result = computeAccessibleLabelStyles('0f0');
|
|
37
|
+
expect(result).not.toBeNull();
|
|
38
|
+
expect(result?.bg).toBe('#00ff001a');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should handle uppercase hex', () => {
|
|
42
|
+
const result = computeAccessibleLabelStyles('#FF5733');
|
|
43
|
+
expect(result).not.toBeNull();
|
|
44
|
+
expect(result?.bg).toBe('#ff57331a');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should handle mixed case hex', () => {
|
|
48
|
+
const result = computeAccessibleLabelStyles('#AbCdEf');
|
|
49
|
+
expect(result).not.toBeNull();
|
|
50
|
+
expect(result?.bg).toBe('#abcdef1a');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('Named color inputs', () => {
|
|
55
|
+
it('should handle "red" color name', () => {
|
|
56
|
+
const result = computeAccessibleLabelStyles('red');
|
|
57
|
+
expect(result).not.toBeNull();
|
|
58
|
+
expect(result?.bg).toBe('#ef44441a');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should handle "blue" color name', () => {
|
|
62
|
+
const result = computeAccessibleLabelStyles('blue');
|
|
63
|
+
expect(result).not.toBeNull();
|
|
64
|
+
expect(result?.bg).toBe('#3b82f61a');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should handle "green" color name', () => {
|
|
68
|
+
const result = computeAccessibleLabelStyles('green');
|
|
69
|
+
expect(result).not.toBeNull();
|
|
70
|
+
expect(result?.bg).toBe('#22c55e1a');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should handle "purple" color name', () => {
|
|
74
|
+
const result = computeAccessibleLabelStyles('purple');
|
|
75
|
+
expect(result).not.toBeNull();
|
|
76
|
+
expect(result?.bg).toBe('#a855f71a');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should handle "orange" color name', () => {
|
|
80
|
+
const result = computeAccessibleLabelStyles('orange');
|
|
81
|
+
expect(result).not.toBeNull();
|
|
82
|
+
expect(result?.bg).toBe('#f973161a');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should handle "pink" color name', () => {
|
|
86
|
+
const result = computeAccessibleLabelStyles('pink');
|
|
87
|
+
expect(result).not.toBeNull();
|
|
88
|
+
expect(result?.bg).toBe('#ec48991a');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle "cyan" color name', () => {
|
|
92
|
+
const result = computeAccessibleLabelStyles('cyan');
|
|
93
|
+
expect(result).not.toBeNull();
|
|
94
|
+
expect(result?.bg).toBe('#06b6d41a');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle "gray" color name', () => {
|
|
98
|
+
const result = computeAccessibleLabelStyles('gray');
|
|
99
|
+
expect(result).not.toBeNull();
|
|
100
|
+
expect(result?.bg).toBe('#6b72801a');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should handle Tailwind color names', () => {
|
|
104
|
+
const tailwindColors = [
|
|
105
|
+
'red',
|
|
106
|
+
'orange',
|
|
107
|
+
'amber',
|
|
108
|
+
'yellow',
|
|
109
|
+
'lime',
|
|
110
|
+
'green',
|
|
111
|
+
'emerald',
|
|
112
|
+
'teal',
|
|
113
|
+
'cyan',
|
|
114
|
+
'sky',
|
|
115
|
+
'blue',
|
|
116
|
+
'indigo',
|
|
117
|
+
'violet',
|
|
118
|
+
'purple',
|
|
119
|
+
'fuchsia',
|
|
120
|
+
'pink',
|
|
121
|
+
'rose',
|
|
122
|
+
'gray',
|
|
123
|
+
'slate',
|
|
124
|
+
'zinc',
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
for (const color of tailwindColors) {
|
|
128
|
+
const result = computeAccessibleLabelStyles(color);
|
|
129
|
+
expect(result).not.toBeNull();
|
|
130
|
+
expect(result?.bg).toMatch(/^#[0-9a-f]{6}1a$/);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('Invalid inputs', () => {
|
|
136
|
+
it('should return null for empty string', () => {
|
|
137
|
+
const result = computeAccessibleLabelStyles('');
|
|
138
|
+
expect(result).toBeNull();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should return null for unknown color name', () => {
|
|
142
|
+
const result = computeAccessibleLabelStyles('unknowncolor');
|
|
143
|
+
expect(result).toBeNull();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should return null for invalid hex (too short)', () => {
|
|
147
|
+
const result = computeAccessibleLabelStyles('#ab');
|
|
148
|
+
expect(result).toBeNull();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should return null for invalid hex (too long)', () => {
|
|
152
|
+
const result = computeAccessibleLabelStyles('#1234567');
|
|
153
|
+
expect(result).toBeNull();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should return null for invalid hex characters', () => {
|
|
157
|
+
const result = computeAccessibleLabelStyles('#gggggg');
|
|
158
|
+
expect(result).toBeNull();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should return null for special characters', () => {
|
|
162
|
+
const result = computeAccessibleLabelStyles('@#$%^&');
|
|
163
|
+
expect(result).toBeNull();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('Result structure', () => {
|
|
168
|
+
it('should return object with bg, border, and text properties', () => {
|
|
169
|
+
const result = computeAccessibleLabelStyles('#3b82f6');
|
|
170
|
+
expect(result).toHaveProperty('bg');
|
|
171
|
+
expect(result).toHaveProperty('border');
|
|
172
|
+
expect(result).toHaveProperty('text');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should have bg with opacity suffix 1a (10%)', () => {
|
|
176
|
+
const result = computeAccessibleLabelStyles('#ff0000');
|
|
177
|
+
expect(result?.bg).toMatch(/1a$/);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should have border with opacity suffix 4d (30%)', () => {
|
|
181
|
+
const result = computeAccessibleLabelStyles('#ff0000');
|
|
182
|
+
expect(result?.border).toMatch(/4d$/);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should have text as full hex color', () => {
|
|
186
|
+
const result = computeAccessibleLabelStyles('#3b82f6');
|
|
187
|
+
expect(result?.text).toMatch(/^#[0-9a-f]{6}$/);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('Luminance-based text color adjustment', () => {
|
|
192
|
+
it('should lighten text for very dark colors (low luminance)', () => {
|
|
193
|
+
// Very dark color (not pure black) - should be lightened
|
|
194
|
+
// Pure black (#000000) cannot be lightened via HSL multiplication (0 * factor = 0)
|
|
195
|
+
const result = computeAccessibleLabelStyles('#1a1a1a');
|
|
196
|
+
expect(result).not.toBeNull();
|
|
197
|
+
// Text should be lighter than original
|
|
198
|
+
expect(result?.text).not.toBe('#1a1a1a');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should darken text for very light colors (high luminance)', () => {
|
|
202
|
+
// Very light color - should be darkened
|
|
203
|
+
const result = computeAccessibleLabelStyles('#ffffff');
|
|
204
|
+
expect(result).not.toBeNull();
|
|
205
|
+
// Text should be darker than original
|
|
206
|
+
expect(result?.text).not.toBe('#ffffff');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should keep text as-is for mid-range luminance colors', () => {
|
|
210
|
+
// Mid-range color - should stay relatively similar
|
|
211
|
+
const result = computeAccessibleLabelStyles('#808080');
|
|
212
|
+
expect(result).not.toBeNull();
|
|
213
|
+
// Text should be close to original (gray)
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Edge cases', () => {
|
|
218
|
+
it('should handle whitespace in input', () => {
|
|
219
|
+
const result = computeAccessibleLabelStyles(' #3b82f6 ');
|
|
220
|
+
expect(result).not.toBeNull();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should normalize all output to lowercase', () => {
|
|
224
|
+
const result = computeAccessibleLabelStyles('#AABBCC');
|
|
225
|
+
expect(result?.bg).toBe('#aabbcc1a');
|
|
226
|
+
expect(result?.border).toBe('#aabbcc4d');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should handle pure white correctly', () => {
|
|
230
|
+
const result = computeAccessibleLabelStyles('#ffffff');
|
|
231
|
+
expect(result).not.toBeNull();
|
|
232
|
+
expect(result?.bg).toBe('#ffffff1a');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should handle pure black correctly', () => {
|
|
236
|
+
const result = computeAccessibleLabelStyles('#000000');
|
|
237
|
+
expect(result).not.toBeNull();
|
|
238
|
+
expect(result?.bg).toBe('#0000001a');
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
generateFunName,
|
|
4
|
+
getAvatarPlaceholder,
|
|
5
|
+
getInitials,
|
|
6
|
+
} from '../name-helper';
|
|
7
|
+
|
|
8
|
+
describe('Name Helper', () => {
|
|
9
|
+
describe('getInitials', () => {
|
|
10
|
+
it('returns empty string for null', () => {
|
|
11
|
+
expect(getInitials(null)).toBe('');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('returns empty string for undefined', () => {
|
|
15
|
+
expect(getInitials(undefined)).toBe('');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns empty string for empty string', () => {
|
|
19
|
+
expect(getInitials('')).toBe('');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns empty string for whitespace only', () => {
|
|
23
|
+
expect(getInitials(' ')).toBe('');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns single initial for single word', () => {
|
|
27
|
+
expect(getInitials('John')).toBe('J');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns two initials for two words', () => {
|
|
31
|
+
expect(getInitials('John Doe')).toBe('JD');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns first and last initials for multiple words', () => {
|
|
35
|
+
expect(getInitials('John Middle Doe')).toBe('JD');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('handles lowercase input', () => {
|
|
39
|
+
expect(getInitials('john doe')).toBe('JD');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('handles hyphenated names', () => {
|
|
43
|
+
expect(getInitials('Mary-Jane Watson')).toBe('MW');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('handles names with apostrophes', () => {
|
|
47
|
+
expect(getInitials("O'Brien Smith")).toBe('OS');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('handles names with tabs and newlines', () => {
|
|
51
|
+
expect(getInitials('John\tDoe')).toBe('JD');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('handles articles like "van"', () => {
|
|
55
|
+
expect(getInitials('Ludwig van Beethoven')).toBe('LB');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('handles articles like "de"', () => {
|
|
59
|
+
expect(getInitials('Leonardo da Vinci')).toBe('LV');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('handles capitalized prefix like "Van"', () => {
|
|
63
|
+
expect(getInitials('Van Helsing')).toBe('VH');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('handles multiple spaces', () => {
|
|
67
|
+
expect(getInitials('John Doe')).toBe('JD');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('handles trailing spaces', () => {
|
|
71
|
+
expect(getInitials(' John Doe ')).toBe('JD');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('getAvatarPlaceholder', () => {
|
|
76
|
+
it('generates correct URL for simple name', () => {
|
|
77
|
+
const url = getAvatarPlaceholder('John Doe');
|
|
78
|
+
expect(url).toBe('https://ui-avatars.com/api/?name=John%20Doe');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('encodes special characters', () => {
|
|
82
|
+
const url = getAvatarPlaceholder('John & Jane');
|
|
83
|
+
expect(url).toBe('https://ui-avatars.com/api/?name=John%20%26%20Jane');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('handles empty string', () => {
|
|
87
|
+
const url = getAvatarPlaceholder('');
|
|
88
|
+
expect(url).toBe('https://ui-avatars.com/api/?name=');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('handles names with unicode characters', () => {
|
|
92
|
+
const url = getAvatarPlaceholder('Nguyễn Văn');
|
|
93
|
+
expect(url).toContain('https://ui-avatars.com/api/?name=');
|
|
94
|
+
expect(url).toContain('Nguy%E1%BB%85n');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('generateFunName', () => {
|
|
99
|
+
it('generates consistent name for same ID', () => {
|
|
100
|
+
const name1 = generateFunName({ id: 'test-id-123' });
|
|
101
|
+
const name2 = generateFunName({ id: 'test-id-123' });
|
|
102
|
+
expect(name1).toBe(name2);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('generates different names for different IDs', () => {
|
|
106
|
+
const name1 = generateFunName({ id: 'test-id-1' });
|
|
107
|
+
const name2 = generateFunName({ id: 'test-id-2' });
|
|
108
|
+
expect(name1).not.toBe(name2);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('generates English name by default', () => {
|
|
112
|
+
const name = generateFunName({ id: 'test-id' });
|
|
113
|
+
// Should contain English adjective + animal + emoji at end
|
|
114
|
+
expect(name).toMatch(/^[A-Z][a-z]+ [A-Z][a-z]+/);
|
|
115
|
+
// Should end with an emoji (emoji are typically > 1 char in JS)
|
|
116
|
+
expect(name.length).toBeGreaterThan(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('generates Vietnamese name when locale is vi', () => {
|
|
120
|
+
const name = generateFunName({ id: 'test-id', locale: 'vi' });
|
|
121
|
+
// Vietnamese format puts animal first, then adjective
|
|
122
|
+
expect(name).toBeDefined();
|
|
123
|
+
expect(typeof name).toBe('string');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('defaults to English for invalid locale', () => {
|
|
127
|
+
const name = generateFunName({ id: 'test-id', locale: 'invalid-locale' });
|
|
128
|
+
// Should fall back to English pattern
|
|
129
|
+
expect(name).toBeDefined();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('includes emoji in the name', () => {
|
|
133
|
+
const name = generateFunName({ id: 'test-id' });
|
|
134
|
+
// Name should end with an emoji (unicode character > 127)
|
|
135
|
+
const lastChar = name.charCodeAt(name.length - 1);
|
|
136
|
+
expect(lastChar).toBeGreaterThan(127);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('handles empty ID string', () => {
|
|
140
|
+
const name = generateFunName({ id: '' });
|
|
141
|
+
expect(name).toBeDefined();
|
|
142
|
+
expect(typeof name).toBe('string');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('handles very long ID', () => {
|
|
146
|
+
const longId = 'a'.repeat(1000);
|
|
147
|
+
const name = generateFunName({ id: longId });
|
|
148
|
+
expect(name).toBeDefined();
|
|
149
|
+
expect(typeof name).toBe('string');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('handles special characters in ID', () => {
|
|
153
|
+
const name = generateFunName({ id: '!@#$%^&*()' });
|
|
154
|
+
expect(name).toBeDefined();
|
|
155
|
+
expect(typeof name).toBe('string');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|