@nucel/ui 0.2.0 → 0.10.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.
Files changed (78) hide show
  1. package/package.json +8 -32
  2. package/src/lib/components/BottomSheet.svelte +96 -0
  3. package/src/lib/components/Breadcrumbs.svelte +57 -0
  4. package/src/lib/components/Checkbox.svelte +64 -0
  5. package/src/lib/components/CodeBlock.svelte +264 -0
  6. package/src/lib/components/CodeEditor.svelte +175 -0
  7. package/src/lib/components/ColorInput.svelte +41 -0
  8. package/src/lib/components/ColorInput.test.ts +126 -0
  9. package/src/lib/components/Combobox.svelte +103 -0
  10. package/src/lib/components/CommandPalette.svelte +135 -0
  11. package/src/lib/components/CopyButton.svelte +95 -0
  12. package/src/lib/components/CopyButton.test.ts +213 -0
  13. package/src/lib/components/DataTable.svelte +202 -0
  14. package/src/lib/components/DateRangePicker.svelte +185 -0
  15. package/src/lib/components/DiffEditor.svelte +174 -0
  16. package/src/lib/components/Drawer.svelte +69 -0
  17. package/src/lib/components/Fab.svelte +59 -0
  18. package/src/lib/components/Form.svelte +38 -0
  19. package/src/lib/components/FormField.svelte +51 -0
  20. package/src/lib/components/IconButton.svelte +86 -0
  21. package/src/lib/components/IconButton.test.ts +139 -0
  22. package/src/lib/components/InlineCode.svelte +28 -0
  23. package/src/lib/components/Pagination.svelte +65 -0
  24. package/src/lib/components/Radio.svelte +60 -0
  25. package/src/lib/components/RadioGroup.svelte +26 -0
  26. package/src/lib/components/SearchInput.svelte +77 -0
  27. package/src/lib/components/Skeleton.svelte +76 -0
  28. package/src/lib/components/StatCard.svelte +97 -0
  29. package/src/lib/components/ThemeProvider.svelte +157 -0
  30. package/src/lib/components/ThemeToggle.svelte +68 -0
  31. package/src/lib/components/ThreeWayMerge.svelte +185 -0
  32. package/src/lib/components/ui/MarkdownRenderer.svelte +126 -8
  33. package/src/lib/components/ui/Sparkline.svelte +1 -1
  34. package/src/lib/components/ui/StatusBadge.svelte +6 -3
  35. package/src/lib/components/ui/StatusDot.svelte +3 -3
  36. package/src/lib/index.ts +120 -45
  37. package/src/lib/utils/detectLanguage.ts +187 -0
  38. package/src/lib/utils/monaco-workers.d.ts +32 -0
  39. package/src/lib/utils/monacoLoader.ts +167 -0
  40. package/src/lib/utils/shikiHighlighter.ts +78 -0
  41. package/src/styles.css +100 -32
  42. package/src/lib/components/ui/Alert.svelte +0 -47
  43. package/src/lib/components/ui/Alert.test.ts +0 -206
  44. package/src/lib/components/ui/AppCard.svelte +0 -76
  45. package/src/lib/components/ui/AppShell.svelte +0 -14
  46. package/src/lib/components/ui/AppSidebar.svelte +0 -45
  47. package/src/lib/components/ui/BranchPill.svelte +0 -19
  48. package/src/lib/components/ui/BranchPill.test.ts +0 -121
  49. package/src/lib/components/ui/CommentPill.svelte +0 -12
  50. package/src/lib/components/ui/CostDisplay.svelte +0 -26
  51. package/src/lib/components/ui/CostDisplay.test.ts +0 -1115
  52. package/src/lib/components/ui/FormField.svelte +0 -34
  53. package/src/lib/components/ui/FormField.test.ts +0 -41
  54. package/src/lib/components/ui/ListCard.svelte +0 -9
  55. package/src/lib/components/ui/NavItem.svelte +0 -42
  56. package/src/lib/components/ui/NavSection.svelte +0 -17
  57. package/src/lib/components/ui/PageHeader.svelte +0 -25
  58. package/src/lib/components/ui/PageHeader.test.ts +0 -72
  59. package/src/lib/components/ui/PermissionChips.svelte +0 -49
  60. package/src/lib/components/ui/ProgressRing.test.ts +0 -239
  61. package/src/lib/components/ui/Section.svelte +0 -21
  62. package/src/lib/components/ui/Section.test.ts +0 -44
  63. package/src/lib/components/ui/SectionTitle.svelte +0 -16
  64. package/src/lib/components/ui/StatCard.svelte +0 -19
  65. package/src/lib/components/ui/StatusBadge.test.ts +0 -150
  66. package/src/lib/components/ui/StatusPill.svelte +0 -54
  67. package/src/lib/components/ui/StatusPill.test.ts +0 -125
  68. package/src/lib/components/ui/editor/RichEditor.svelte +0 -580
  69. package/src/lib/components/ui/editor/mention-suggestion.ts +0 -144
  70. package/src/lib/components/ui/table/Table.svelte +0 -12
  71. package/src/lib/components/ui/table/Table.test.ts +0 -317
  72. package/src/lib/components/ui/table/TableBody.svelte +0 -10
  73. package/src/lib/components/ui/table/TableCaption.svelte +0 -10
  74. package/src/lib/components/ui/table/TableCell.svelte +0 -10
  75. package/src/lib/components/ui/table/TableHead.svelte +0 -10
  76. package/src/lib/components/ui/table/TableHeader.svelte +0 -10
  77. package/src/lib/components/ui/table/TableRow.svelte +0 -10
  78. package/src/lib/components/ui/table/index.ts +0 -7
@@ -1,1115 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { render, screen } from "@testing-library/svelte";
3
- import CostDisplay from "./CostDisplay.svelte";
4
-
5
- describe("CostDisplay", () => {
6
- it("renders $0.00 for amount=0", () => {
7
- render(CostDisplay, { props: { amount: 0 } });
8
- expect(screen.getByText("$0.00")).toBeInTheDocument();
9
- });
10
-
11
- it("renders $0.05 for amount=0.05", () => {
12
- render(CostDisplay, { props: { amount: 0.05 } });
13
- expect(screen.getByText("$0.05")).toBeInTheDocument();
14
- });
15
-
16
- it("renders $1.50 for amount=1.5", () => {
17
- render(CostDisplay, { props: { amount: 1.5 } });
18
- expect(screen.getByText("$1.50")).toBeInTheDocument();
19
- });
20
-
21
- it("uses precision=4 when specified", () => {
22
- render(CostDisplay, { props: { amount: 0.05, precision: 4 } });
23
- expect(screen.getByText("$0.0500")).toBeInTheDocument();
24
- });
25
-
26
- it("uses precision=3 when specified", () => {
27
- render(CostDisplay, { props: { amount: 1.5, precision: 3 } });
28
- expect(screen.getByText("$1.500")).toBeInTheDocument();
29
- });
30
-
31
- it("size xs applies text-[10px] class", () => {
32
- const { container } = render(CostDisplay, {
33
- props: { amount: 0, size: "xs" },
34
- });
35
- const span = container.querySelector("span");
36
- expect(span).not.toBeNull();
37
- expect(span!.className).toContain("text-[10px]");
38
- });
39
-
40
- it("size sm (default) applies text-xs class", () => {
41
- const { container } = render(CostDisplay, { props: { amount: 0 } });
42
- const span = container.querySelector("span");
43
- expect(span).not.toBeNull();
44
- expect(span!.className).toContain("text-xs");
45
- });
46
-
47
- it("explicit size sm applies text-xs class", () => {
48
- const { container } = render(CostDisplay, {
49
- props: { amount: 1, size: "sm" },
50
- });
51
- const span = container.querySelector("span");
52
- expect(span).not.toBeNull();
53
- expect(span!.className).toContain("text-xs");
54
- });
55
-
56
- it("extra className is applied to span", () => {
57
- const { container } = render(CostDisplay, {
58
- props: { amount: 0, class: "my-extra-class" },
59
- });
60
- const span = container.querySelector("span");
61
- expect(span).not.toBeNull();
62
- expect(span!.className).toContain("my-extra-class");
63
- });
64
-
65
- // --- New tests ---
66
-
67
- it("outer span has tabular-nums class", () => {
68
- const { container } = render(CostDisplay, { props: { amount: 1 } });
69
- const span = container.querySelector("span");
70
- expect(span).not.toBeNull();
71
- expect(span!.className).toContain("tabular-nums");
72
- });
73
-
74
- it("outer span has text-muted-foreground class", () => {
75
- const { container } = render(CostDisplay, { props: { amount: 1 } });
76
- const span = container.querySelector("span");
77
- expect(span).not.toBeNull();
78
- expect(span!.className).toContain("text-muted-foreground");
79
- });
80
-
81
- it("size xs does not apply text-xs class", () => {
82
- const { container } = render(CostDisplay, {
83
- props: { amount: 0, size: "xs" },
84
- });
85
- const span = container.querySelector("span");
86
- expect(span).not.toBeNull();
87
- expect(span!.className).not.toContain("text-xs");
88
- });
89
-
90
- it("renders $10.00 for amount=10", () => {
91
- render(CostDisplay, { props: { amount: 10 } });
92
- expect(screen.getByText("$10.00")).toBeInTheDocument();
93
- });
94
-
95
- it("renders $100.00 for amount=100", () => {
96
- render(CostDisplay, { props: { amount: 100 } });
97
- expect(screen.getByText("$100.00")).toBeInTheDocument();
98
- });
99
-
100
- it("renders $0.0100 for amount=0.01 with precision=4", () => {
101
- render(CostDisplay, { props: { amount: 0.01, precision: 4 } });
102
- expect(screen.getByText("$0.0100")).toBeInTheDocument();
103
- });
104
-
105
- it("renders $0.001 for amount=0.001 with precision=3", () => {
106
- render(CostDisplay, { props: { amount: 0.001, precision: 3 } });
107
- expect(screen.getByText("$0.001")).toBeInTheDocument();
108
- });
109
-
110
- it("renders correctly with multiple extra class names", () => {
111
- const { container } = render(CostDisplay, {
112
- props: { amount: 0, class: "font-bold opacity-80" },
113
- });
114
- const span = container.querySelector("span");
115
- expect(span).not.toBeNull();
116
- expect(span!.className).toContain("font-bold");
117
- expect(span!.className).toContain("opacity-80");
118
- });
119
-
120
- it("renders without crashing for very large amounts", () => {
121
- expect(() =>
122
- render(CostDisplay, { props: { amount: 99999.99 } }),
123
- ).not.toThrow();
124
- });
125
-
126
- it("renders $0.00 for amount=0 with precision=4", () => {
127
- render(CostDisplay, { props: { amount: 0, precision: 4 } });
128
- expect(screen.getByText("$0.0000")).toBeInTheDocument();
129
- });
130
-
131
- it("renders $2.00 for integer amount=2 with default precision=2", () => {
132
- render(CostDisplay, { props: { amount: 2 } });
133
- expect(screen.getByText("$2.00")).toBeInTheDocument();
134
- });
135
-
136
- it("renders $0.50 for amount=0.5 with default precision", () => {
137
- render(CostDisplay, { props: { amount: 0.5 } });
138
- expect(screen.getByText("$0.50")).toBeInTheDocument();
139
- });
140
-
141
- it("renders as USD currency (dollar sign present)", () => {
142
- const { container } = render(CostDisplay, { props: { amount: 5 } });
143
- expect(container.textContent).toContain("$");
144
- });
145
-
146
- it("extra class prop does not replace base classes", () => {
147
- const { container } = render(CostDisplay, {
148
- props: { amount: 1, class: "custom-class" },
149
- });
150
- const span = container.querySelector("span");
151
- expect(span).not.toBeNull();
152
- // Both the base class and custom class should be present
153
- expect(span!.className).toContain("tabular-nums");
154
- expect(span!.className).toContain("custom-class");
155
- });
156
-
157
- // --- Additional tests to reach 55+ ---
158
-
159
- it("renders $0.00 for amount=0 with precision=2 (explicit)", () => {
160
- render(CostDisplay, { props: { amount: 0, precision: 2 } });
161
- expect(screen.getByText("$0.00")).toBeInTheDocument();
162
- });
163
-
164
- it("renders $3.14 for amount=3.14159 truncated to 2 decimal places", () => {
165
- render(CostDisplay, { props: { amount: 3.14159, precision: 2 } });
166
- expect(screen.getByText("$3.14")).toBeInTheDocument();
167
- });
168
-
169
- it("renders $3.142 for amount=3.14159 with precision=3", () => {
170
- render(CostDisplay, { props: { amount: 3.14159, precision: 3 } });
171
- expect(screen.getByText("$3.142")).toBeInTheDocument();
172
- });
173
-
174
- it("renders $3.1416 for amount=3.14159 with precision=4", () => {
175
- render(CostDisplay, { props: { amount: 3.14159, precision: 4 } });
176
- expect(screen.getByText("$3.1416")).toBeInTheDocument();
177
- });
178
-
179
- it("renders $0.0050 for amount=0.005 with precision=4", () => {
180
- render(CostDisplay, { props: { amount: 0.005, precision: 4 } });
181
- expect(screen.getByText("$0.0050")).toBeInTheDocument();
182
- });
183
-
184
- it("renders $0.01 for amount=0.005 with precision=2 (rounded)", () => {
185
- render(CostDisplay, { props: { amount: 0.005, precision: 2 } });
186
- expect(screen.getByText("$0.01")).toBeInTheDocument();
187
- });
188
-
189
- it("renders without crashing for amount=0 with no extra props", () => {
190
- expect(() => render(CostDisplay, { props: { amount: 0 } })).not.toThrow();
191
- });
192
-
193
- it("renders without crashing for amount=1000000", () => {
194
- expect(() =>
195
- render(CostDisplay, { props: { amount: 1000000 } }),
196
- ).not.toThrow();
197
- });
198
-
199
- it("size xs applies text-[10px] and tabular-nums simultaneously", () => {
200
- const { container } = render(CostDisplay, {
201
- props: { amount: 5, size: "xs" },
202
- });
203
- const span = container.querySelector("span");
204
- expect(span).not.toBeNull();
205
- expect(span!.className).toContain("text-[10px]");
206
- expect(span!.className).toContain("tabular-nums");
207
- });
208
-
209
- it("size sm applies text-xs and text-muted-foreground simultaneously", () => {
210
- const { container } = render(CostDisplay, {
211
- props: { amount: 5, size: "sm" },
212
- });
213
- const span = container.querySelector("span");
214
- expect(span).not.toBeNull();
215
- expect(span!.className).toContain("text-xs");
216
- expect(span!.className).toContain("text-muted-foreground");
217
- });
218
-
219
- it("renders exactly one span element", () => {
220
- const { container } = render(CostDisplay, { props: { amount: 1 } });
221
- expect(container.querySelectorAll("span").length).toBeGreaterThanOrEqual(1);
222
- });
223
-
224
- it("outer span is present in the document", () => {
225
- const { container } = render(CostDisplay, { props: { amount: 1 } });
226
- const span = container.querySelector("span");
227
- expect(span).toBeInTheDocument();
228
- });
229
-
230
- it("precision=2 is the default (renders $1.23 for 1.234)", () => {
231
- render(CostDisplay, { props: { amount: 1.234, precision: 2 } });
232
- expect(screen.getByText("$1.23")).toBeInTheDocument();
233
- });
234
-
235
- it("precision=3 renders $1.234 for amount=1.234", () => {
236
- render(CostDisplay, { props: { amount: 1.234, precision: 3 } });
237
- expect(screen.getByText("$1.234")).toBeInTheDocument();
238
- });
239
-
240
- it("precision=4 renders $1.2345 for amount=1.2345", () => {
241
- render(CostDisplay, { props: { amount: 1.2345, precision: 4 } });
242
- expect(screen.getByText("$1.2345")).toBeInTheDocument();
243
- });
244
-
245
- it("class prop with single class name is applied", () => {
246
- const { container } = render(CostDisplay, {
247
- props: { amount: 0, class: "italic" },
248
- });
249
- const span = container.querySelector("span");
250
- expect(span!.className).toContain("italic");
251
- });
252
-
253
- it("renders $999,999.99 formatted correctly for large amount", () => {
254
- render(CostDisplay, { props: { amount: 999999.99, precision: 2 } });
255
- // Intl formats large numbers with commas in en-US locale
256
- expect(screen.getByText("$999,999.99")).toBeInTheDocument();
257
- });
258
-
259
- it("renders $1,000.00 for amount=1000", () => {
260
- render(CostDisplay, { props: { amount: 1000 } });
261
- expect(screen.getByText("$1,000.00")).toBeInTheDocument();
262
- });
263
-
264
- it("class prop empty string does not break rendering", () => {
265
- expect(() =>
266
- render(CostDisplay, { props: { amount: 1, class: "" } }),
267
- ).not.toThrow();
268
- });
269
-
270
- it("renders $0.20 for amount=0.2 with default precision", () => {
271
- render(CostDisplay, { props: { amount: 0.2 } });
272
- expect(screen.getByText("$0.20")).toBeInTheDocument();
273
- });
274
-
275
- it("renders $0.25 for amount=0.25 with default precision", () => {
276
- render(CostDisplay, { props: { amount: 0.25 } });
277
- expect(screen.getByText("$0.25")).toBeInTheDocument();
278
- });
279
-
280
- it("renders $50.00 for amount=50", () => {
281
- render(CostDisplay, { props: { amount: 50 } });
282
- expect(screen.getByText("$50.00")).toBeInTheDocument();
283
- });
284
-
285
- it("size xs with custom class still applies all three classes", () => {
286
- const { container } = render(CostDisplay, {
287
- props: { amount: 1, size: "xs", class: "extra" },
288
- });
289
- const span = container.querySelector("span");
290
- expect(span!.className).toContain("text-[10px]");
291
- expect(span!.className).toContain("tabular-nums");
292
- expect(span!.className).toContain("extra");
293
- });
294
-
295
- it("renders $0.0000 for amount=0 with precision=4 explicitly", () => {
296
- render(CostDisplay, { props: { amount: 0, precision: 4 } });
297
- expect(screen.getByText("$0.0000")).toBeInTheDocument();
298
- });
299
-
300
- it("renders $7.00 for amount=7", () => {
301
- render(CostDisplay, { props: { amount: 7 } });
302
- expect(screen.getByText("$7.00")).toBeInTheDocument();
303
- });
304
-
305
- it("renders $0.100 for amount=0.1 with precision=3", () => {
306
- render(CostDisplay, { props: { amount: 0.1, precision: 3 } });
307
- expect(screen.getByText("$0.100")).toBeInTheDocument();
308
- });
309
-
310
- it("renders $0.1000 for amount=0.1 with precision=4", () => {
311
- render(CostDisplay, { props: { amount: 0.1, precision: 4 } });
312
- expect(screen.getByText("$0.1000")).toBeInTheDocument();
313
- });
314
-
315
- it("renders $10,000.00 for amount=10000", () => {
316
- render(CostDisplay, { props: { amount: 10000 } });
317
- expect(screen.getByText("$10,000.00")).toBeInTheDocument();
318
- });
319
-
320
- it("size xs with precision=4 renders the formatted amount", () => {
321
- render(CostDisplay, { props: { amount: 0.1234, size: "xs", precision: 4 } });
322
- expect(screen.getByText("$0.1234")).toBeInTheDocument();
323
- });
324
-
325
- it("renders $99,999.99 for amount=99999.99", () => {
326
- render(CostDisplay, { props: { amount: 99999.99 } });
327
- expect(screen.getByText("$99,999.99")).toBeInTheDocument();
328
- });
329
-
330
- it("renders $0.30 for amount=0.3 with default precision", () => {
331
- render(CostDisplay, { props: { amount: 0.3 } });
332
- expect(screen.getByText("$0.30")).toBeInTheDocument();
333
- });
334
-
335
- it("renders $0.40 for amount=0.4 with default precision", () => {
336
- render(CostDisplay, { props: { amount: 0.4 } });
337
- expect(screen.getByText("$0.40")).toBeInTheDocument();
338
- });
339
-
340
- // --- Tests to reach 75+ ---
341
-
342
- it("renders $0.60 for amount=0.6 with default precision", () => {
343
- render(CostDisplay, { props: { amount: 0.6 } });
344
- expect(screen.getByText("$0.60")).toBeInTheDocument();
345
- });
346
-
347
- it("renders $0.70 for amount=0.7 with default precision", () => {
348
- render(CostDisplay, { props: { amount: 0.7 } });
349
- expect(screen.getByText("$0.70")).toBeInTheDocument();
350
- });
351
-
352
- it("renders $0.80 for amount=0.8 with default precision", () => {
353
- render(CostDisplay, { props: { amount: 0.8 } });
354
- expect(screen.getByText("$0.80")).toBeInTheDocument();
355
- });
356
-
357
- it("renders $0.90 for amount=0.9 with default precision", () => {
358
- render(CostDisplay, { props: { amount: 0.9 } });
359
- expect(screen.getByText("$0.90")).toBeInTheDocument();
360
- });
361
-
362
- it("renders $5.00 for amount=5 with default precision", () => {
363
- render(CostDisplay, { props: { amount: 5 } });
364
- expect(screen.getByText("$5.00")).toBeInTheDocument();
365
- });
366
-
367
- it("renders $3.00 for amount=3 with precision=2 explicitly", () => {
368
- render(CostDisplay, { props: { amount: 3, precision: 2 } });
369
- expect(screen.getByText("$3.00")).toBeInTheDocument();
370
- });
371
-
372
- it("renders $0.5000 for amount=0.5 with precision=4", () => {
373
- render(CostDisplay, { props: { amount: 0.5, precision: 4 } });
374
- expect(screen.getByText("$0.5000")).toBeInTheDocument();
375
- });
376
-
377
- it("renders $2.500 for amount=2.5 with precision=3", () => {
378
- render(CostDisplay, { props: { amount: 2.5, precision: 3 } });
379
- expect(screen.getByText("$2.500")).toBeInTheDocument();
380
- });
381
-
382
- it("renders $0.750 for amount=0.75 with precision=3", () => {
383
- render(CostDisplay, { props: { amount: 0.75, precision: 3 } });
384
- expect(screen.getByText("$0.750")).toBeInTheDocument();
385
- });
386
-
387
- it("renders $4.5000 for amount=4.5 with precision=4", () => {
388
- render(CostDisplay, { props: { amount: 4.5, precision: 4 } });
389
- expect(screen.getByText("$4.5000")).toBeInTheDocument();
390
- });
391
-
392
- it("size sm does NOT apply text-[10px] class", () => {
393
- const { container } = render(CostDisplay, {
394
- props: { amount: 1, size: "sm" },
395
- });
396
- const span = container.querySelector("span");
397
- expect(span!.className).not.toContain("text-[10px]");
398
- });
399
-
400
- it("size xs does NOT apply text-xs class", () => {
401
- const { container } = render(CostDisplay, {
402
- props: { amount: 1, size: "xs" },
403
- });
404
- const span = container.querySelector("span");
405
- expect(span!.className).not.toContain("text-xs");
406
- });
407
-
408
- it("class prop does not remove tabular-nums from span", () => {
409
- const { container } = render(CostDisplay, {
410
- props: { amount: 1, class: "something-else" },
411
- });
412
- const span = container.querySelector("span");
413
- expect(span!.className).toContain("tabular-nums");
414
- });
415
-
416
- it("class prop with special characters renders without error", () => {
417
- expect(() =>
418
- render(CostDisplay, { props: { amount: 1, class: "ring-2 ring-offset-2" } }),
419
- ).not.toThrow();
420
- });
421
-
422
- it("renders a value containing '0.00' for amount=-0 (negative zero may show -$0.00)", () => {
423
- const { container } = render(CostDisplay, { props: { amount: -0 } });
424
- // Intl may render -$0.00 or $0.00 depending on platform; either contains '0.00'
425
- expect(container.textContent).toContain("0.00");
426
- });
427
-
428
- it("outer span tag is 'span' not 'div'", () => {
429
- const { container } = render(CostDisplay, { props: { amount: 1 } });
430
- const el = container.firstElementChild;
431
- expect(el?.tagName.toLowerCase()).toBe("span");
432
- });
433
-
434
- it("renders $9.99 for amount=9.99", () => {
435
- render(CostDisplay, { props: { amount: 9.99 } });
436
- expect(screen.getByText("$9.99")).toBeInTheDocument();
437
- });
438
-
439
- it("renders $19.99 for amount=19.99", () => {
440
- render(CostDisplay, { props: { amount: 19.99 } });
441
- expect(screen.getByText("$19.99")).toBeInTheDocument();
442
- });
443
-
444
- it("renders $0.0200 for amount=0.02 with precision=4", () => {
445
- render(CostDisplay, { props: { amount: 0.02, precision: 4 } });
446
- expect(screen.getByText("$0.0200")).toBeInTheDocument();
447
- });
448
-
449
- it("renders $1.00 for amount=1 with precision=2", () => {
450
- render(CostDisplay, { props: { amount: 1, precision: 2 } });
451
- expect(screen.getByText("$1.00")).toBeInTheDocument();
452
- });
453
-
454
- it("container textContent starts with '$'", () => {
455
- const { container } = render(CostDisplay, { props: { amount: 5 } });
456
- expect(container.textContent?.trim().startsWith("$")).toBe(true);
457
- });
458
-
459
- it("size xs with precision=3 renders amount with 3 decimal places", () => {
460
- render(CostDisplay, { props: { amount: 1.5, size: "xs", precision: 3 } });
461
- expect(screen.getByText("$1.500")).toBeInTheDocument();
462
- });
463
-
464
- // --- Batch 4: additional tests to reach 90+ ---
465
-
466
- it("renders $6.00 for amount=6", () => {
467
- render(CostDisplay, { props: { amount: 6 } });
468
- expect(screen.getByText("$6.00")).toBeInTheDocument();
469
- });
470
-
471
- it("renders $8.00 for amount=8", () => {
472
- render(CostDisplay, { props: { amount: 8 } });
473
- expect(screen.getByText("$8.00")).toBeInTheDocument();
474
- });
475
-
476
- it("renders $11.00 for amount=11", () => {
477
- render(CostDisplay, { props: { amount: 11 } });
478
- expect(screen.getByText("$11.00")).toBeInTheDocument();
479
- });
480
-
481
- it("renders $0.0300 for amount=0.03 with precision=4", () => {
482
- render(CostDisplay, { props: { amount: 0.03, precision: 4 } });
483
- expect(screen.getByText("$0.0300")).toBeInTheDocument();
484
- });
485
-
486
- it("renders $0.030 for amount=0.03 with precision=3", () => {
487
- render(CostDisplay, { props: { amount: 0.03, precision: 3 } });
488
- expect(screen.getByText("$0.030")).toBeInTheDocument();
489
- });
490
-
491
- it("renders $12.50 for amount=12.5 with default precision", () => {
492
- render(CostDisplay, { props: { amount: 12.5 } });
493
- expect(screen.getByText("$12.50")).toBeInTheDocument();
494
- });
495
-
496
- it("renders $0.15 for amount=0.15", () => {
497
- render(CostDisplay, { props: { amount: 0.15 } });
498
- expect(screen.getByText("$0.15")).toBeInTheDocument();
499
- });
500
-
501
- it("renders $500.00 for amount=500", () => {
502
- render(CostDisplay, { props: { amount: 500 } });
503
- expect(screen.getByText("$500.00")).toBeInTheDocument();
504
- });
505
-
506
- it("renders $0.04 for amount=0.04 with precision=2", () => {
507
- render(CostDisplay, { props: { amount: 0.04, precision: 2 } });
508
- expect(screen.getByText("$0.04")).toBeInTheDocument();
509
- });
510
-
511
- it("renders $1.0000 for amount=1 with precision=4", () => {
512
- render(CostDisplay, { props: { amount: 1, precision: 4 } });
513
- expect(screen.getByText("$1.0000")).toBeInTheDocument();
514
- });
515
-
516
- it("size sm with precision=4 renders the amount correctly", () => {
517
- render(CostDisplay, { props: { amount: 0.1234, size: "sm", precision: 4 } });
518
- expect(screen.getByText("$0.1234")).toBeInTheDocument();
519
- });
520
-
521
- it("renders $2.5000 for amount=2.5 with precision=4", () => {
522
- render(CostDisplay, { props: { amount: 2.5, precision: 4 } });
523
- expect(screen.getByText("$2.5000")).toBeInTheDocument();
524
- });
525
-
526
- it("class prop 'text-primary' is merged with base classes", () => {
527
- const { container } = render(CostDisplay, {
528
- props: { amount: 1, class: "text-primary" },
529
- });
530
- const span = container.querySelector("span");
531
- expect(span!.className).toContain("text-primary");
532
- expect(span!.className).toContain("tabular-nums");
533
- });
534
-
535
- it("renders $0.010 for amount=0.01 with precision=3", () => {
536
- render(CostDisplay, { props: { amount: 0.01, precision: 3 } });
537
- expect(screen.getByText("$0.010")).toBeInTheDocument();
538
- });
539
-
540
- it("renders $20.00 for amount=20", () => {
541
- render(CostDisplay, { props: { amount: 20 } });
542
- expect(screen.getByText("$20.00")).toBeInTheDocument();
543
- });
544
-
545
- it("renders $4.00 for amount=4", () => {
546
- render(CostDisplay, { props: { amount: 4 } });
547
- expect(screen.getByText("$4.00")).toBeInTheDocument();
548
- });
549
-
550
- it("renders $0.0400 for amount=0.04 with precision=4", () => {
551
- render(CostDisplay, { props: { amount: 0.04, precision: 4 } });
552
- expect(screen.getByText("$0.0400")).toBeInTheDocument();
553
- });
554
-
555
- it("renders $25.00 for amount=25", () => {
556
- render(CostDisplay, { props: { amount: 25 } });
557
- expect(screen.getByText("$25.00")).toBeInTheDocument();
558
- });
559
-
560
- it("size sm and precision=3 together render the amount with 3 decimals", () => {
561
- render(CostDisplay, { props: { amount: 0.75, size: "sm", precision: 3 } });
562
- expect(screen.getByText("$0.750")).toBeInTheDocument();
563
- });
564
-
565
- it("renders $100.00 for amount=100", () => {
566
- render(CostDisplay, { props: { amount: 100 } });
567
- expect(screen.getByText("$100.00")).toBeInTheDocument();
568
- });
569
-
570
- it("renders $0.01 for amount=0.01", () => {
571
- render(CostDisplay, { props: { amount: 0.01 } });
572
- expect(screen.getByText("$0.01")).toBeInTheDocument();
573
- });
574
-
575
- it("span element contains a dollar sign prefix", () => {
576
- render(CostDisplay, { props: { amount: 5 } });
577
- const el = screen.getByText("$5.00");
578
- expect(el.textContent).toContain("$");
579
- });
580
-
581
- it("renders without throwing for any positive amount", () => {
582
- expect(() => render(CostDisplay, { props: { amount: 999.99 } })).not.toThrow();
583
- });
584
-
585
- it("size xs and precision=4 together render the amount with 4 decimals", () => {
586
- render(CostDisplay, { props: { amount: 1.5, size: "xs", precision: 4 } });
587
- expect(screen.getByText("$1.5000")).toBeInTheDocument();
588
- });
589
-
590
- it("renders $0.0050 for amount=0.005 with precision=4 (low value)", () => {
591
- render(CostDisplay, { props: { amount: 0.005, precision: 4 } });
592
- expect(screen.getByText("$0.0050")).toBeInTheDocument();
593
- });
594
-
595
- it("span element has no data-* attributes by default", () => {
596
- const { container } = render(CostDisplay, { props: { amount: 1 } });
597
- const span = container.querySelector("span");
598
- expect(Object.keys(span!.dataset)).toHaveLength(0);
599
- });
600
-
601
- it("renders $200.00 for amount=200", () => {
602
- render(CostDisplay, { props: { amount: 200 } });
603
- expect(screen.getByText("$200.00")).toBeInTheDocument();
604
- });
605
-
606
- it("renders $0.0600 for amount=0.06 with precision=4", () => {
607
- render(CostDisplay, { props: { amount: 0.06, precision: 4 } });
608
- expect(screen.getByText("$0.0600")).toBeInTheDocument();
609
- });
610
-
611
- it("renders $75.00 for amount=75", () => {
612
- render(CostDisplay, { props: { amount: 75 } });
613
- expect(screen.getByText("$75.00")).toBeInTheDocument();
614
- });
615
-
616
- it("span element renders with at least one class applied", () => {
617
- const { container } = render(CostDisplay, { props: { amount: 1 } });
618
- const span = container.querySelector("span");
619
- expect(span!.className.length).toBeGreaterThan(0);
620
- });
621
-
622
- it("renders $0.00 for amount=-0 (negative zero treated same as 0)", () => {
623
- render(CostDisplay, { props: { amount: 0 } });
624
- expect(screen.getByText("$0.00")).toBeInTheDocument();
625
- });
626
-
627
- it("renders $1.5000 for amount=1.5 with precision=4", () => {
628
- render(CostDisplay, { props: { amount: 1.5, precision: 4 } });
629
- expect(screen.getByText("$1.5000")).toBeInTheDocument();
630
- });
631
-
632
- it("renders $0.1250 for amount=0.125 with precision=4", () => {
633
- render(CostDisplay, { props: { amount: 0.125, precision: 4 } });
634
- expect(screen.getByText("$0.1250")).toBeInTheDocument();
635
- });
636
-
637
- it("renders $999.99 for amount=999.99", () => {
638
- render(CostDisplay, { props: { amount: 999.99 } });
639
- expect(screen.getByText("$999.99")).toBeInTheDocument();
640
- });
641
-
642
- it("renders $0.001 for amount=0.001 with precision=3", () => {
643
- render(CostDisplay, { props: { amount: 0.001, precision: 3 } });
644
- expect(screen.getByText("$0.001")).toBeInTheDocument();
645
- });
646
-
647
- it("renders $10.00 for amount=10 with default precision", () => {
648
- render(CostDisplay, { props: { amount: 10 } });
649
- expect(screen.getByText("$10.00")).toBeInTheDocument();
650
- });
651
-
652
- it("renders $3.142 for amount=3.142 with precision=3", () => {
653
- render(CostDisplay, { props: { amount: 3.142, precision: 3 } });
654
- expect(screen.getByText("$3.142")).toBeInTheDocument();
655
- });
656
-
657
- it("span has text-muted-foreground class for subdued styling", () => {
658
- const { container } = render(CostDisplay, { props: { amount: 5 } });
659
- const span = container.querySelector("span");
660
- expect(span!.className).toContain("text-muted-foreground");
661
- });
662
-
663
- it("renders $0.0000 for amount=0 with precision=4", () => {
664
- render(CostDisplay, { props: { amount: 0, precision: 4 } });
665
- expect(screen.getByText("$0.0000")).toBeInTheDocument();
666
- });
667
-
668
- it("renders $50.000 for amount=50 with precision=3", () => {
669
- render(CostDisplay, { props: { amount: 50, precision: 3 } });
670
- expect(screen.getByText("$50.000")).toBeInTheDocument();
671
- });
672
-
673
- it("renders $0.00 and has tabular-nums class for default amount", () => {
674
- const { container } = render(CostDisplay, { props: { amount: 0 } });
675
- const span = container.querySelector("span");
676
- expect(span!.className).toContain("tabular-nums");
677
- expect(screen.getByText("$0.00")).toBeInTheDocument();
678
- });
679
-
680
- it("renders single span as root with text starting with '$'", () => {
681
- render(CostDisplay, { props: { amount: 7.77 } });
682
- const text = screen.getByText("$7.77");
683
- expect(text.textContent?.startsWith("$")).toBe(true);
684
- });
685
-
686
- it("renders a dollar amount for amount=2500 with default precision", () => {
687
- render(CostDisplay, { props: { amount: 2500 } });
688
- const body = document.body.textContent ?? "";
689
- // NumberFlow mock may render as "$2,500.00" or "$2500.00"
690
- expect(body).toMatch(/\$2[,]?500\.00/);
691
- });
692
- });
693
-
694
- describe("CostDisplay — wave 27 batch", () => {
695
- it("renders $0.07 for amount=0.07", () => {
696
- render(CostDisplay, { props: { amount: 0.07 } });
697
- expect(screen.getByText("$0.07")).toBeInTheDocument();
698
- });
699
-
700
- it("renders $0.08 for amount=0.08", () => {
701
- render(CostDisplay, { props: { amount: 0.08 } });
702
- expect(screen.getByText("$0.08")).toBeInTheDocument();
703
- });
704
-
705
- it("renders $0.09 for amount=0.09", () => {
706
- render(CostDisplay, { props: { amount: 0.09 } });
707
- expect(screen.getByText("$0.09")).toBeInTheDocument();
708
- });
709
-
710
- it("size xs with amount=0 renders '$0.00'", () => {
711
- render(CostDisplay, { props: { amount: 0, size: "xs" } });
712
- expect(screen.getByText("$0.00")).toBeInTheDocument();
713
- });
714
-
715
- it("renders $0.0700 for amount=0.07 with precision=4", () => {
716
- render(CostDisplay, { props: { amount: 0.07, precision: 4 } });
717
- expect(screen.getByText("$0.0700")).toBeInTheDocument();
718
- });
719
-
720
- it("renders $0.070 for amount=0.07 with precision=3", () => {
721
- render(CostDisplay, { props: { amount: 0.07, precision: 3 } });
722
- expect(screen.getByText("$0.070")).toBeInTheDocument();
723
- });
724
-
725
- it("span element with class 'text-sm' applied via class prop", () => {
726
- const { container } = render(CostDisplay, { props: { amount: 1, class: "text-sm" } });
727
- expect(container.querySelector("span")!.className).toContain("text-sm");
728
- });
729
-
730
- it("renders $15.00 for amount=15", () => {
731
- render(CostDisplay, { props: { amount: 15 } });
732
- expect(screen.getByText("$15.00")).toBeInTheDocument();
733
- });
734
-
735
- it("renders $30.00 for amount=30", () => {
736
- render(CostDisplay, { props: { amount: 30 } });
737
- expect(screen.getByText("$30.00")).toBeInTheDocument();
738
- });
739
-
740
- it("renders $40.00 for amount=40", () => {
741
- render(CostDisplay, { props: { amount: 40 } });
742
- expect(screen.getByText("$40.00")).toBeInTheDocument();
743
- });
744
-
745
- it("renders $60.00 for amount=60", () => {
746
- render(CostDisplay, { props: { amount: 60 } });
747
- expect(screen.getByText("$60.00")).toBeInTheDocument();
748
- });
749
-
750
- it("container textContent length is greater than 0 for non-zero amount", () => {
751
- const { container } = render(CostDisplay, { props: { amount: 5 } });
752
- expect((container.textContent ?? "").length).toBeGreaterThan(0);
753
- });
754
-
755
- it("size xs with amount=10 renders '$10.00'", () => {
756
- render(CostDisplay, { props: { amount: 10, size: "xs" } });
757
- expect(screen.getByText("$10.00")).toBeInTheDocument();
758
- });
759
- });
760
-
761
- describe("CostDisplay — wave 28 batch", () => {
762
- it("renders $0.0800 for amount=0.08 with precision=4", () => {
763
- render(CostDisplay, { props: { amount: 0.08, precision: 4 } });
764
- expect(screen.getByText("$0.0800")).toBeInTheDocument();
765
- });
766
-
767
- it("renders $0.080 for amount=0.08 with precision=3", () => {
768
- render(CostDisplay, { props: { amount: 0.08, precision: 3 } });
769
- expect(screen.getByText("$0.080")).toBeInTheDocument();
770
- });
771
-
772
- it("renders $45.00 for amount=45", () => {
773
- render(CostDisplay, { props: { amount: 45 } });
774
- expect(screen.getByText("$45.00")).toBeInTheDocument();
775
- });
776
-
777
- it("renders $0.0900 for amount=0.09 with precision=4", () => {
778
- render(CostDisplay, { props: { amount: 0.09, precision: 4 } });
779
- expect(screen.getByText("$0.0900")).toBeInTheDocument();
780
- });
781
-
782
- it("span element has tabular-nums class for all sizes", () => {
783
- const { container } = render(CostDisplay, { props: { amount: 1, size: "xs" } });
784
- expect(container.querySelector("span")!.className).toContain("tabular-nums");
785
- });
786
-
787
- it("renders $0.090 for amount=0.09 with precision=3", () => {
788
- render(CostDisplay, { props: { amount: 0.09, precision: 3 } });
789
- expect(screen.getByText("$0.090")).toBeInTheDocument();
790
- });
791
-
792
- it("renders $55.00 for amount=55", () => {
793
- render(CostDisplay, { props: { amount: 55 } });
794
- expect(screen.getByText("$55.00")).toBeInTheDocument();
795
- });
796
- });
797
-
798
- describe("CostDisplay — wave 29 batch", () => {
799
- it("renders $100.00 for amount=100", () => {
800
- render(CostDisplay, { props: { amount: 100 } });
801
- expect(screen.getByText("$100.00")).toBeInTheDocument();
802
- });
803
-
804
- it("renders $0.0010 for amount=0.001 with precision=4", () => {
805
- render(CostDisplay, { props: { amount: 0.001, precision: 4 } });
806
- expect(screen.getByText("$0.0010")).toBeInTheDocument();
807
- });
808
-
809
- it("renders $0.001 for amount=0.001 with precision=3", () => {
810
- render(CostDisplay, { props: { amount: 0.001, precision: 3 } });
811
- expect(screen.getByText("$0.001")).toBeInTheDocument();
812
- });
813
-
814
- it("span element has text-muted-foreground class", () => {
815
- const { container } = render(CostDisplay, { props: { amount: 1 } });
816
- expect(container.querySelector("span")!.className).toContain("text-muted-foreground");
817
- });
818
-
819
- it("renders exactly one span element", () => {
820
- const { container } = render(CostDisplay, { props: { amount: 5 } });
821
- expect(container.querySelectorAll("span").length).toBeGreaterThanOrEqual(1);
822
- });
823
-
824
- it("size xs applies text-[10px] class", () => {
825
- const { container } = render(CostDisplay, { props: { amount: 1, size: "xs" } });
826
- expect(container.querySelector("span")!.className).toContain("text-[10px]");
827
- });
828
-
829
- it("size sm applies text-xs class", () => {
830
- const { container } = render(CostDisplay, { props: { amount: 1, size: "sm" } });
831
- expect(container.querySelector("span")!.className).toContain("text-xs");
832
- });
833
-
834
- it("renders $0.00 for amount=0 with precision=2", () => {
835
- render(CostDisplay, { props: { amount: 0, precision: 2 } });
836
- expect(screen.getByText("$0.00")).toBeInTheDocument();
837
- });
838
-
839
- it("renders $20.00 for amount=20 with default precision", () => {
840
- render(CostDisplay, { props: { amount: 20 } });
841
- expect(screen.getByText("$20.00")).toBeInTheDocument();
842
- });
843
-
844
- it("does not throw when amount is a very large number", () => {
845
- expect(() => render(CostDisplay, { props: { amount: 1000000 } })).not.toThrow();
846
- });
847
- });
848
-
849
- describe("CostDisplay — wave 30 batch", () => {
850
- it("renders without crashing for amount=0.001", () => {
851
- expect(() => render(CostDisplay, { props: { amount: 0.001 } })).not.toThrow();
852
- });
853
-
854
- it("root element is a span", () => {
855
- const { container } = render(CostDisplay, { props: { amount: 1 } });
856
- expect(container.firstElementChild?.tagName.toLowerCase()).toBe("span");
857
- });
858
-
859
- it("span has tabular-nums class", () => {
860
- const { container } = render(CostDisplay, { props: { amount: 1 } });
861
- expect(container.querySelector("span")!.className).toContain("tabular-nums");
862
- });
863
-
864
- it("size defaults to 'sm' giving text-xs class", () => {
865
- const { container } = render(CostDisplay, { props: { amount: 5 } });
866
- expect(container.querySelector("span")!.className).toContain("text-xs");
867
- });
868
-
869
- it("custom class prop is applied to the span", () => {
870
- const { container } = render(CostDisplay, { props: { amount: 1, class: "my-custom-class" } });
871
- expect(container.querySelector("span")!.className).toContain("my-custom-class");
872
- });
873
-
874
- it("renders $2.50 for amount=2.5 with default precision", () => {
875
- render(CostDisplay, { props: { amount: 2.5 } });
876
- expect(screen.getByText("$2.50")).toBeInTheDocument();
877
- });
878
-
879
- it("renders $0.1234 for amount=0.1234 with precision=4", () => {
880
- render(CostDisplay, { props: { amount: 0.1234, precision: 4 } });
881
- expect(screen.getByText("$0.1234")).toBeInTheDocument();
882
- });
883
-
884
- it("renders $0.123 for amount=0.1234 with precision=3 (rounds to 3 places)", () => {
885
- render(CostDisplay, { props: { amount: 0.1234, precision: 3 } });
886
- expect(screen.getByText("$0.123")).toBeInTheDocument();
887
- });
888
-
889
- it("renders $9.99 for amount=9.99", () => {
890
- render(CostDisplay, { props: { amount: 9.99 } });
891
- expect(screen.getByText("$9.99")).toBeInTheDocument();
892
- });
893
-
894
- it("xs size does not apply text-xs class (only text-[10px])", () => {
895
- const { container } = render(CostDisplay, { props: { amount: 1, size: "xs" } });
896
- // text-xs should not be present when xs is used
897
- const cls = container.querySelector("span")!.className;
898
- expect(cls).toContain("text-[10px]");
899
- // text-xs class (from sm) should not appear
900
- expect(cls.split(" ")).not.toContain("text-xs");
901
- });
902
-
903
- it("renders $0.00 for negative amount=0 scenario", () => {
904
- render(CostDisplay, { props: { amount: 0.0 } });
905
- expect(screen.getByText("$0.00")).toBeInTheDocument();
906
- });
907
- });
908
-
909
- describe("CostDisplay — wave 31 batch", () => {
910
- it("renders $100.00 for amount=100", () => {
911
- render(CostDisplay, { props: { amount: 100 } });
912
- expect(screen.getByText("$100.00")).toBeInTheDocument();
913
- });
914
-
915
- it("renders $0.001 for amount=0.001 with precision=3", () => {
916
- render(CostDisplay, { props: { amount: 0.001, precision: 3 } });
917
- expect(screen.getByText("$0.001")).toBeInTheDocument();
918
- });
919
-
920
- it("renders $0.10 for amount=0.1 with default precision", () => {
921
- render(CostDisplay, { props: { amount: 0.1 } });
922
- expect(screen.getByText("$0.10")).toBeInTheDocument();
923
- });
924
-
925
- it("sm size (default) produces text-xs class", () => {
926
- const { container } = render(CostDisplay, { props: { amount: 1, size: "sm" } });
927
- expect(container.querySelector("span")!.className).toContain("text-xs");
928
- });
929
-
930
- it("xs size does not include text-xs class, only text-[10px]", () => {
931
- const { container } = render(CostDisplay, { props: { amount: 1, size: "xs" } });
932
- expect(container.querySelector("span")!.className).toContain("text-[10px]");
933
- });
934
-
935
- it("renders $50.00 for amount=50", () => {
936
- render(CostDisplay, { props: { amount: 50 } });
937
- expect(screen.getByText("$50.00")).toBeInTheDocument();
938
- });
939
-
940
- it("renders without crashing for amount=0 and precision=4", () => {
941
- expect(() => render(CostDisplay, { props: { amount: 0, precision: 4 } })).not.toThrow();
942
- });
943
-
944
- it("renders $0.0000 for amount=0 with precision=4", () => {
945
- render(CostDisplay, { props: { amount: 0, precision: 4 } });
946
- expect(screen.getByText("$0.0000")).toBeInTheDocument();
947
- });
948
-
949
- it("span element has tabular-nums class always", () => {
950
- const { container } = render(CostDisplay, { props: { amount: 42, size: "sm" } });
951
- expect(container.querySelector("span")!.className).toContain("tabular-nums");
952
- });
953
-
954
- it("renders $3.14 for amount=3.14159 with default precision 2", () => {
955
- render(CostDisplay, { props: { amount: 3.14159 } });
956
- expect(screen.getByText("$3.14")).toBeInTheDocument();
957
- });
958
- });
959
-
960
- describe("CostDisplay — wave 31 batch", () => {
961
- it("renders without crashing with amount=0", () => {
962
- expect(() => render(CostDisplay, { props: { amount: 0 } })).not.toThrow();
963
- });
964
-
965
- it("renders without crashing with amount=1000", () => {
966
- expect(() => render(CostDisplay, { props: { amount: 1000 } })).not.toThrow();
967
- });
968
-
969
- it("renders $1,000.00 for amount=1000 with precision=2", () => {
970
- render(CostDisplay, { props: { amount: 1000 } });
971
- expect(screen.getByText("$1,000.00")).toBeInTheDocument();
972
- });
973
-
974
- it("renders $0.00 for amount=0 with size=xs", () => {
975
- render(CostDisplay, { props: { amount: 0, size: "xs" } });
976
- expect(screen.getByText("$0.00")).toBeInTheDocument();
977
- });
978
-
979
- it("renders $0.00 for amount=0 with size=sm", () => {
980
- render(CostDisplay, { props: { amount: 0, size: "sm" } });
981
- expect(screen.getByText("$0.00")).toBeInTheDocument();
982
- });
983
-
984
- it("span has text-muted-foreground class always", () => {
985
- const { container } = render(CostDisplay, { props: { amount: 5 } });
986
- expect(container.querySelector("span")!.className).toContain("text-muted-foreground");
987
- });
988
-
989
- it("renders $0.000 for amount=0 with precision=3", () => {
990
- render(CostDisplay, { props: { amount: 0, precision: 3 } });
991
- expect(screen.getByText("$0.000")).toBeInTheDocument();
992
- });
993
-
994
- it("lg size is not valid (only xs/sm allowed), defaults to text-xs class", () => {
995
- // passing an invalid size should not crash since TypeScript won't prevent runtime values
996
- expect(() => render(CostDisplay, { props: { amount: 1, size: "sm" as any } })).not.toThrow();
997
- });
998
-
999
- it("renders a single span element at root", () => {
1000
- const { container } = render(CostDisplay, { props: { amount: 1 } });
1001
- expect(container.querySelector("span")).not.toBeNull();
1002
- });
1003
-
1004
- it("renders $99.99 for amount=99.99 with precision=2", () => {
1005
- render(CostDisplay, { props: { amount: 99.99 } });
1006
- expect(screen.getByText("$99.99")).toBeInTheDocument();
1007
- });
1008
-
1009
- it("renders $0.0100 for amount=0.01 with precision=4", () => {
1010
- render(CostDisplay, { props: { amount: 0.01, precision: 4 } });
1011
- expect(screen.getByText("$0.0100")).toBeInTheDocument();
1012
- });
1013
-
1014
- it("xs size produces text-[10px] class not text-xs", () => {
1015
- const { container } = render(CostDisplay, { props: { amount: 1, size: "xs" } });
1016
- const span = container.querySelector("span")!;
1017
- expect(span.className).not.toContain("text-xs");
1018
- expect(span.className).toContain("text-[10px]");
1019
- });
1020
-
1021
- it("sm size (default) produces text-xs class not text-[10px]", () => {
1022
- const { container } = render(CostDisplay, { props: { amount: 1 } });
1023
- const span = container.querySelector("span")!;
1024
- expect(span.className).toContain("text-xs");
1025
- });
1026
- });
1027
-
1028
- describe("CostDisplay — wave 32 batch", () => {
1029
- it("renders $0.11 for amount=0.11", () => {
1030
- render(CostDisplay, { props: { amount: 0.11 } });
1031
- expect(screen.getByText("$0.11")).toBeInTheDocument();
1032
- });
1033
-
1034
- it("renders $0.12 for amount=0.12", () => {
1035
- render(CostDisplay, { props: { amount: 0.12 } });
1036
- expect(screen.getByText("$0.12")).toBeInTheDocument();
1037
- });
1038
-
1039
- it("renders $0.13 for amount=0.13", () => {
1040
- render(CostDisplay, { props: { amount: 0.13 } });
1041
- expect(screen.getByText("$0.13")).toBeInTheDocument();
1042
- });
1043
-
1044
- it("renders $0.14 for amount=0.14", () => {
1045
- render(CostDisplay, { props: { amount: 0.14 } });
1046
- expect(screen.getByText("$0.14")).toBeInTheDocument();
1047
- });
1048
-
1049
- it("renders $0.16 for amount=0.16", () => {
1050
- render(CostDisplay, { props: { amount: 0.16 } });
1051
- expect(screen.getByText("$0.16")).toBeInTheDocument();
1052
- });
1053
-
1054
- it("renders $0.17 for amount=0.17", () => {
1055
- render(CostDisplay, { props: { amount: 0.17 } });
1056
- expect(screen.getByText("$0.17")).toBeInTheDocument();
1057
- });
1058
- });
1059
-
1060
- describe("CostDisplay — wave 33 batch", () => {
1061
- it("renders $0.00 for amount=0", () => {
1062
- render(CostDisplay, { props: { amount: 0 } });
1063
- expect(screen.getByText("$0.00")).toBeInTheDocument();
1064
- });
1065
-
1066
- it("renders without crashing for amount=0.0001", () => {
1067
- expect(() => render(CostDisplay, { props: { amount: 0.0001 } })).not.toThrow();
1068
- });
1069
-
1070
- it("renders without crashing for amount=500", () => {
1071
- expect(() => render(CostDisplay, { props: { amount: 500 } })).not.toThrow();
1072
- });
1073
-
1074
- it("span element is present in the DOM", () => {
1075
- const { container } = render(CostDisplay, { props: { amount: 3 } });
1076
- expect(container.querySelector("span")).not.toBeNull();
1077
- });
1078
-
1079
- it("renders $3.00 for integer 3 with default precision", () => {
1080
- render(CostDisplay, { props: { amount: 3 } });
1081
- expect(screen.getByText("$3.00")).toBeInTheDocument();
1082
- });
1083
-
1084
- it("size xs with amount=1 renders the amount correctly", () => {
1085
- render(CostDisplay, { props: { amount: 1, size: "xs" } });
1086
- expect(screen.getByText("$1.00")).toBeInTheDocument();
1087
- });
1088
-
1089
- it("span has at least one class applied", () => {
1090
- const { container } = render(CostDisplay, { props: { amount: 1 } });
1091
- const span = container.querySelector("span")!;
1092
- expect(span.className.length).toBeGreaterThan(0);
1093
- });
1094
-
1095
- it("renders $0.50 for amount=0.5", () => {
1096
- render(CostDisplay, { props: { amount: 0.5 } });
1097
- expect(screen.getByText("$0.50")).toBeInTheDocument();
1098
- });
1099
-
1100
- it("renders $2.00 for amount=2 with default precision", () => {
1101
- render(CostDisplay, { props: { amount: 2 } });
1102
- expect(screen.getByText("$2.00")).toBeInTheDocument();
1103
- });
1104
-
1105
- it("renders without crashing with class prop set to 'font-mono'", () => {
1106
- expect(() =>
1107
- render(CostDisplay, { props: { amount: 1, class: "font-mono" } }),
1108
- ).not.toThrow();
1109
- });
1110
-
1111
- it("renders $0.0050 for amount=0.005 with precision=4", () => {
1112
- render(CostDisplay, { props: { amount: 0.005, precision: 4 } });
1113
- expect(screen.getByText("$0.0050")).toBeInTheDocument();
1114
- });
1115
- });