@ncds/ui-admin 1.8.26-alpha.1 → 1.8.26-alpha.2

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,88 @@
1
+ import path from 'node:path';
2
+ import { compile as compileSass } from 'sass';
3
+ import { describe, expect, it } from 'vitest';
4
+ // :-webkit-autofill 은 jsdom 에서 재현할 수 없으므로, 컴파일된 CSS 에서 상태별 규칙을 검사한다.
5
+ // (assets/scripts/dropdown/__tests__/dropdownPortal.test.ts 와 같은 방식 — 컴포넌트 SCSS 엔트리를 직접 컴파일)
6
+ const INPUT_SCSS_PATH = path.resolve(__dirname, '../../../../../assets/styles/components/input-base/_index.scss');
7
+ const compiledInputCss = compileSass(INPUT_SCSS_PATH).css;
8
+ /** 선택자 → 선언 목록. 같은 선택자가 여러 규칙에 나오면 선언을 이어 붙인다. */
9
+ const parseRules = (css) => {
10
+ const rules = new Map();
11
+ for (const [, selectorList, body] of css.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
12
+ const declarations = body
13
+ .split(';')
14
+ .map((declaration) => declaration.trim().replace(/\s+/g, ' '))
15
+ .filter(Boolean);
16
+ for (const selector of selectorList.split(',').map((selector) => selector.trim().replace(/\s+/g, ' '))) {
17
+ rules.set(selector, [...(rules.get(selector) ?? []), ...declarations]);
18
+ }
19
+ }
20
+ return rules;
21
+ };
22
+ const rules = parseRules(compiledInputCss);
23
+ const declarationsOf = (selector) => rules.get(selector) ?? [];
24
+ const AUTOFILL_PSEUDOS = [
25
+ ':-webkit-autofill',
26
+ ':-webkit-autofill:hover',
27
+ ':-webkit-autofill:focus',
28
+ ':-webkit-autofill:active',
29
+ ];
30
+ const ALLOWED_AUTOFILL_PROPERTIES = ['-webkit-box-shadow', '-webkit-text-fill-color', 'caret-color'];
31
+ describe('Input autofill 스타일 — 기본 상태', () => {
32
+ it.each(AUTOFILL_PSEUDOS)('.ncua-input input%s 는 배경 --base-white, 글자·caret --gray-700 이다', (pseudo) => {
33
+ // Given: 컴파일된 Input CSS 에서
34
+ // When: 기본 상태 autofill 규칙을 찾으면
35
+ const declarations = declarationsOf(`.ncua-input input${pseudo}`);
36
+ // Then: 배경은 흰색 inset box-shadow, 글자·caret 은 기본 글자색이다
37
+ expect(declarations).toContain('-webkit-box-shadow: 0 0 0 30px var(--base-white) inset !important');
38
+ expect(declarations).toContain('-webkit-text-fill-color: var(--gray-700)');
39
+ expect(declarations).toContain('caret-color: var(--gray-700)');
40
+ });
41
+ });
42
+ describe('Input autofill 스타일 — disabled 상태', () => {
43
+ it.each(AUTOFILL_PSEUDOS)('.ncua-input.is-disabled input%s 는 배경 --gray-50, 글자·caret --gray-300 이다', (pseudo) => {
44
+ // Given: 컴파일된 Input CSS 에서
45
+ // When: disabled 상태 autofill 규칙을 찾으면
46
+ const declarations = declarationsOf(`.ncua-input.is-disabled input${pseudo}`);
47
+ // Then: 배경·글자색이 기존 disabled 스타일과 같다
48
+ expect(declarations).toContain('-webkit-box-shadow: 0 0 0 30px var(--gray-50) inset !important');
49
+ expect(declarations).toContain('-webkit-text-fill-color: var(--gray-300)');
50
+ expect(declarations).toContain('caret-color: var(--gray-300)');
51
+ });
52
+ });
53
+ describe('Input autofill 스타일 — 규칙 범위 제한', () => {
54
+ const autofillSelectors = () => [...rules.keys()].filter((selector) => selector.includes(':-webkit-autofill'));
55
+ it('autofill 규칙은 box-shadow·text-fill-color·caret-color 외 속성을 지정하지 않는다', () => {
56
+ // Given: 모든 autofill 선택자가 존재하는 상태에서 (기본 4 + disabled 4)
57
+ const selectors = autofillSelectors();
58
+ expect(selectors).toHaveLength(AUTOFILL_PSEUDOS.length * 2);
59
+ // When/Then: 각 규칙의 속성은 허용 목록 안에 있다 (값·이벤트에 영향 주는 속성 금지)
60
+ for (const selector of selectors) {
61
+ const properties = declarationsOf(selector).map((declaration) => declaration.split(':')[0].trim());
62
+ expect(properties.every((property) => ALLOWED_AUTOFILL_PROPERTIES.includes(property))).toBe(true);
63
+ }
64
+ });
65
+ it('autofill 규칙에 하드코딩 색상이 없고 CSS 변수만 쓴다', () => {
66
+ // Given/When: autofill 규칙의 선언을 모으면
67
+ const declarations = autofillSelectors().flatMap(declarationsOf);
68
+ // Then: hex·rgb·색 이름 대신 var(--*) 만 쓴다
69
+ expect(declarations.length).toBeGreaterThan(0);
70
+ for (const declaration of declarations) {
71
+ expect(declaration).not.toMatch(/#[0-9a-f]{3,8}\b|rgba?\(|(?<![-\w])white\b/i);
72
+ expect(declaration).toMatch(/var\(--[a-z0-9-]+\)/);
73
+ }
74
+ });
75
+ it('textarea 에는 autofill 규칙을 적용하지 않는다 (ADR-4)', () => {
76
+ // Given/When: autofill 선택자를 모으면
77
+ // Then: textarea 대상 선택자가 없다 (textarea 자체 box-shadow 를 덮어쓰지 않도록)
78
+ expect(autofillSelectors().some((selector) => selector.includes('textarea'))).toBe(false);
79
+ });
80
+ });
81
+ describe('Input 기존 상태 스타일 회귀', () => {
82
+ it('기본 input 글자색은 --gray-700 이다', () => {
83
+ expect(declarationsOf('.ncua-input input')).toContain('color: var(--gray-700)');
84
+ });
85
+ it('disabled input 글자색은 --gray-300 이다', () => {
86
+ expect(declarationsOf('.ncua-input.is-disabled input')).toContain('color: var(--gray-300)');
87
+ });
88
+ });