|
1 | 1 | import { beforeEach, describe, expect, test, vi } from 'vitest'; |
2 | 2 |
|
3 | | -// The plugin is plain CJS — load the validation function by evaluating |
4 | | -// just the relevant pieces. We re-declare the constants and function |
5 | | -// exactly as they appear in app.plugin.js so the test stays in sync. |
6 | | -// ------------------------------------------------------------------ |
7 | | - |
8 | | -const VALID_COLOR_KEYS = [ |
9 | | - 'primary', |
10 | | - 'background', |
11 | | - 'input', |
12 | | - 'danger', |
13 | | - 'success', |
14 | | - 'warning', |
15 | | - 'foreground', |
16 | | - 'mutedForeground', |
17 | | - 'primaryForeground', |
18 | | - 'inputForeground', |
19 | | - 'neutral', |
20 | | - 'border', |
21 | | - 'ring', |
22 | | - 'muted', |
23 | | - 'shadow', |
24 | | -]; |
25 | | - |
26 | | -const HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/; |
27 | | - |
28 | | -function isPlainObject(value) { |
29 | | - return typeof value === 'object' && value !== null && !Array.isArray(value); |
30 | | -} |
31 | | - |
32 | | -function validateThemeJson(theme) { |
33 | | - if (!isPlainObject(theme)) { |
34 | | - throw new Error('Clerk theme: theme JSON must be a plain object'); |
35 | | - } |
36 | | - |
37 | | - const validateColors = (colors, label) => { |
38 | | - if (!isPlainObject(colors)) { |
39 | | - throw new Error(`Clerk theme: ${label} must be an object`); |
40 | | - } |
41 | | - for (const [key, value] of Object.entries(colors)) { |
42 | | - if (!VALID_COLOR_KEYS.includes(key)) { |
43 | | - console.warn(`⚠️ Clerk theme: unknown color key "${key}" in ${label}, ignoring`); |
44 | | - continue; |
45 | | - } |
46 | | - if (typeof value !== 'string' || !HEX_COLOR_REGEX.test(value)) { |
47 | | - throw new Error(`Clerk theme: invalid hex color for ${label}.${key}: "${value}"`); |
48 | | - } |
49 | | - } |
50 | | - }; |
51 | | - |
52 | | - if (theme.colors != null) validateColors(theme.colors, 'colors'); |
53 | | - if (theme.darkColors != null) validateColors(theme.darkColors, 'darkColors'); |
54 | | - |
55 | | - if (theme.design != null) { |
56 | | - if (!isPlainObject(theme.design)) { |
57 | | - throw new Error(`Clerk theme: design must be an object`); |
58 | | - } |
59 | | - if (theme.design.fontFamily != null && typeof theme.design.fontFamily !== 'string') { |
60 | | - throw new Error(`Clerk theme: design.fontFamily must be a string`); |
61 | | - } |
62 | | - if (theme.design.borderRadius != null && typeof theme.design.borderRadius !== 'number') { |
63 | | - throw new Error(`Clerk theme: design.borderRadius must be a number`); |
64 | | - } |
65 | | - } |
66 | | -} |
67 | | - |
68 | | -// ------------------------------------------------------------------ |
| 3 | +const { validateThemeJson } = require('../../app.plugin.js')._testing; |
69 | 4 |
|
70 | 5 | describe('validateThemeJson', () => { |
71 | 6 | beforeEach(() => { |
|
0 commit comments