@ncds/ui-admin 1.8.21-alpha.0 → 1.8.21-alpha.10
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/dist/cjs/assets/scripts/notification/FullWidthNotification.js +17 -6
- package/dist/cjs/assets/scripts/notification/MessageNotification.js +10 -48
- package/dist/cjs/assets/scripts/notification/const/classNames.js +3 -0
- package/dist/cjs/assets/scripts/notification/const/index.js +1 -1
- package/dist/cjs/assets/scripts/notification/const/sizes.js +4 -2
- package/dist/cjs/assets/scripts/notification/messageTemplate.js +106 -0
- package/dist/cjs/assets/scripts/notification/utils.js +40 -4
- package/dist/cjs/constant/notification.js +21 -0
- package/dist/cjs/src/components/forms-and-input/input-base/InputBase.js +52 -34
- package/dist/cjs/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +228 -0
- package/dist/cjs/src/components/forms-and-input/password-input/PasswordInput.js +3 -2
- package/dist/cjs/src/components/forms-and-input/password-input/__tests__/PasswordInput.test.js +59 -0
- package/dist/cjs/src/components/index.js +22 -0
- package/dist/cjs/src/components/layout/ncua-scope/NcuaScope.js +79 -0
- package/dist/cjs/src/components/layout/ncua-scope/index.js +16 -0
- package/dist/cjs/src/components/navigation/pagination/Pagination.js +3 -1
- package/dist/cjs/src/components/navigation/pagination/__tests__/Pagination.test.js +74 -0
- package/dist/cjs/src/components/overlays/notification/FullWidthNotification.js +3 -1
- package/dist/cjs/src/components/overlays/notification/MessageNotification.js +14 -54
- package/dist/cjs/src/components/overlays/notification/MessageNotificationParts.js +92 -0
- package/dist/cjs/src/components/overlays/notification/__tests__/MessageNotification.test.js +246 -0
- package/dist/cjs/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +209 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +259 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/PostcodeSearchModalTip.js +70 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +623 -0
- package/dist/cjs/src/components/overlays/postcode-search-modal/index.js +16 -0
- package/dist/cjs/src/generated/scoped-css.js +9 -0
- package/dist/esm/assets/scripts/notification/FullWidthNotification.js +17 -6
- package/dist/esm/assets/scripts/notification/MessageNotification.js +12 -50
- package/dist/esm/assets/scripts/notification/const/classNames.js +3 -0
- package/dist/esm/assets/scripts/notification/const/index.js +3 -2
- package/dist/esm/assets/scripts/notification/const/sizes.js +4 -2
- package/dist/esm/assets/scripts/notification/messageTemplate.js +100 -0
- package/dist/esm/assets/scripts/notification/utils.js +39 -4
- package/dist/esm/constant/notification.js +15 -0
- package/dist/esm/src/components/forms-and-input/input-base/InputBase.js +52 -34
- package/dist/esm/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +228 -0
- package/dist/esm/src/components/forms-and-input/password-input/PasswordInput.js +3 -2
- package/dist/esm/src/components/forms-and-input/password-input/__tests__/PasswordInput.test.js +56 -0
- package/dist/esm/src/components/index.js +2 -0
- package/dist/esm/src/components/layout/ncua-scope/NcuaScope.js +73 -0
- package/dist/esm/src/components/layout/ncua-scope/index.js +1 -0
- package/dist/esm/src/components/navigation/pagination/Pagination.js +3 -1
- package/dist/esm/src/components/navigation/pagination/__tests__/Pagination.test.js +74 -0
- package/dist/esm/src/components/overlays/notification/FullWidthNotification.js +3 -1
- package/dist/esm/src/components/overlays/notification/MessageNotification.js +15 -55
- package/dist/esm/src/components/overlays/notification/MessageNotificationParts.js +85 -0
- package/dist/esm/src/components/overlays/notification/__tests__/MessageNotification.test.js +243 -0
- package/dist/esm/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +206 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +252 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/PostcodeSearchModalTip.js +63 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +620 -0
- package/dist/esm/src/components/overlays/postcode-search-modal/index.js +1 -0
- package/dist/esm/src/generated/scoped-css.js +3 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +6 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.js +14 -5
- package/dist/temp/assets/scripts/notification/MessageNotification.d.ts +0 -3
- package/dist/temp/assets/scripts/notification/MessageNotification.js +9 -44
- package/dist/temp/assets/scripts/notification/const/classNames.d.ts +1 -0
- package/dist/temp/assets/scripts/notification/const/classNames.js +3 -0
- package/dist/temp/assets/scripts/notification/const/index.d.ts +3 -3
- package/dist/temp/assets/scripts/notification/const/index.js +3 -2
- package/dist/temp/assets/scripts/notification/const/sizes.d.ts +2 -2
- package/dist/temp/assets/scripts/notification/const/sizes.js +4 -2
- package/dist/temp/assets/scripts/notification/const/types.d.ts +30 -2
- package/dist/temp/assets/scripts/notification/messageTemplate.d.ts +15 -0
- package/dist/temp/assets/scripts/notification/messageTemplate.js +79 -0
- package/dist/temp/assets/scripts/notification/utils.d.ts +19 -2
- package/dist/temp/assets/scripts/notification/utils.js +39 -5
- package/dist/temp/constant/notification.d.ts +15 -0
- package/dist/temp/constant/notification.js +15 -0
- package/dist/temp/src/components/forms-and-input/input-base/InputBase.d.ts +1 -1
- package/dist/temp/src/components/forms-and-input/input-base/InputBase.js +43 -26
- package/dist/temp/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +174 -0
- package/dist/temp/src/components/forms-and-input/password-input/PasswordInput.js +2 -1
- package/dist/temp/src/components/forms-and-input/password-input/__tests__/PasswordInput.test.d.ts +1 -0
- package/dist/temp/src/components/forms-and-input/password-input/__tests__/PasswordInput.test.js +48 -0
- package/dist/temp/src/components/index.d.ts +2 -0
- package/dist/temp/src/components/index.js +2 -0
- package/dist/temp/src/components/layout/ncua-scope/NcuaScope.d.ts +32 -0
- package/dist/temp/src/components/layout/ncua-scope/NcuaScope.js +51 -0
- package/dist/temp/src/components/layout/ncua-scope/index.d.ts +1 -0
- package/dist/temp/src/components/layout/ncua-scope/index.js +1 -0
- package/dist/temp/src/components/navigation/pagination/Pagination.js +3 -1
- package/dist/temp/src/components/navigation/pagination/__tests__/Pagination.test.js +74 -0
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.d.ts +6 -0
- package/dist/temp/src/components/overlays/notification/FullWidthNotification.js +3 -2
- package/dist/temp/src/components/overlays/notification/MessageNotification.d.ts +6 -0
- package/dist/temp/src/components/overlays/notification/MessageNotification.js +4 -13
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.d.ts +28 -0
- package/dist/temp/src/components/overlays/notification/MessageNotificationParts.js +28 -0
- package/dist/temp/src/components/overlays/notification/Notification.d.ts +11 -2
- package/dist/temp/src/components/overlays/notification/__tests__/MessageNotification.test.d.ts +1 -0
- package/dist/temp/src/components/overlays/notification/__tests__/MessageNotification.test.js +190 -0
- package/dist/temp/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.d.ts +1 -0
- package/dist/temp/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.js +160 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModal.d.ts +45 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModal.js +125 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModalTip.d.ts +16 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/PostcodeSearchModalTip.js +24 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.d.ts +1 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js +503 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/index.d.ts +1 -0
- package/dist/temp/src/components/overlays/postcode-search-modal/index.js +1 -0
- package/dist/temp/src/generated/scoped-css.d.ts +1 -0
- package/dist/temp/src/generated/scoped-css.js +3 -0
- package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +6 -0
- package/dist/types/assets/scripts/notification/MessageNotification.d.ts +0 -3
- package/dist/types/assets/scripts/notification/const/classNames.d.ts +1 -0
- package/dist/types/assets/scripts/notification/const/index.d.ts +3 -3
- package/dist/types/assets/scripts/notification/const/sizes.d.ts +2 -2
- package/dist/types/assets/scripts/notification/const/types.d.ts +30 -2
- package/dist/types/assets/scripts/notification/messageTemplate.d.ts +15 -0
- package/dist/types/assets/scripts/notification/utils.d.ts +19 -2
- package/dist/types/constant/notification.d.ts +15 -0
- package/dist/types/src/components/forms-and-input/input-base/InputBase.d.ts +1 -1
- package/dist/types/src/components/forms-and-input/password-input/__tests__/PasswordInput.test.d.ts +1 -0
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/layout/ncua-scope/NcuaScope.d.ts +32 -0
- package/dist/types/src/components/layout/ncua-scope/index.d.ts +1 -0
- package/dist/types/src/components/overlays/notification/FullWidthNotification.d.ts +6 -0
- package/dist/types/src/components/overlays/notification/MessageNotification.d.ts +6 -0
- package/dist/types/src/components/overlays/notification/MessageNotificationParts.d.ts +28 -0
- package/dist/types/src/components/overlays/notification/Notification.d.ts +11 -2
- package/dist/types/src/components/overlays/notification/__tests__/MessageNotification.test.d.ts +1 -0
- package/dist/types/src/components/overlays/notification/__tests__/hidePermanentlyLabel.test.d.ts +1 -0
- package/dist/types/src/components/overlays/postcode-search-modal/PostcodeSearchModal.d.ts +45 -0
- package/dist/types/src/components/overlays/postcode-search-modal/PostcodeSearchModalTip.d.ts +16 -0
- package/dist/types/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.d.ts +1 -0
- package/dist/types/src/components/overlays/postcode-search-modal/index.d.ts +1 -0
- package/dist/types/src/generated/scoped-css.d.ts +1 -0
- package/dist/ui-admin/assets/styles/style.css +296 -56
- package/dist/ui-admin/assets/styles/style.scoped.css +8595 -0
- package/package.json +13 -6
package/dist/cjs/src/components/overlays/postcode-search-modal/__tests__/PostcodeSearchModal.test.js
ADDED
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("react");
|
|
4
|
+
var _client = require("react-dom/client");
|
|
5
|
+
var _testUtils = require("react-dom/test-utils");
|
|
6
|
+
var _vitest = require("vitest");
|
|
7
|
+
var _PostcodeSearchModal = require("../PostcodeSearchModal");
|
|
8
|
+
// @vitest-environment jsdom
|
|
9
|
+
|
|
10
|
+
// React 18에서 act() 사용 시 필요한 플래그 (미설정 시 console.error 경고 발생)
|
|
11
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
12
|
+
const PAGE_SIZE = 15;
|
|
13
|
+
/** 한 페이지에 다 들어가는 결과 건수 — Tip 카드 미노출 케이스 */
|
|
14
|
+
const SMALL_RESULT_COUNT = 5;
|
|
15
|
+
/** SMALL_RESULT_COUNT 기준 총 페이지 수 */
|
|
16
|
+
const SMALL_RESULT_TOTAL_PAGE = 1;
|
|
17
|
+
/** 여러 페이지로 나뉘는 결과 건수 — totalPage(3) <= 페이지 그룹 크기(10) */
|
|
18
|
+
const LARGE_RESULT_COUNT = 45;
|
|
19
|
+
/** LARGE_RESULT_COUNT 기준 총 페이지 수 */
|
|
20
|
+
const LARGE_RESULT_TOTAL_PAGE = 3;
|
|
21
|
+
/** 점프 버튼이 뜨는 결과 건수 — totalPage(14) > 페이지 그룹 크기(10) */
|
|
22
|
+
const HUGE_RESULT_COUNT = 200;
|
|
23
|
+
/** 클릭 대상 페이지 번호 */
|
|
24
|
+
const TARGET_PAGE = 3;
|
|
25
|
+
/** 본문을 아래로 내린 상태를 흉내 낼 scrollTop 값 */
|
|
26
|
+
const SCROLLED_OFFSET = 120;
|
|
27
|
+
/** 맨 위로 되돌린 scrollTop 값 */
|
|
28
|
+
const SCROLL_TOP = 0;
|
|
29
|
+
/** 결과 더미 생성 기준값 */
|
|
30
|
+
const ZIP_CODE_BASE = 13529;
|
|
31
|
+
const ROAD_NUMBER_BASE = 242;
|
|
32
|
+
const JIBUN_NUMBER_BASE = 620;
|
|
33
|
+
let root = null;
|
|
34
|
+
let container = null;
|
|
35
|
+
/**
|
|
36
|
+
* Modal 은 createPortal 로 document.body 에 붙으므로 조회 기준은 body 다.
|
|
37
|
+
*/
|
|
38
|
+
function render(props) {
|
|
39
|
+
if (!container) {
|
|
40
|
+
container = document.createElement('div');
|
|
41
|
+
document.body.appendChild(container);
|
|
42
|
+
root = (0, _client.createRoot)(container);
|
|
43
|
+
}
|
|
44
|
+
(0, _testUtils.act)(() => {
|
|
45
|
+
root?.render(/*#__PURE__*/(0, _react.createElement)(_PostcodeSearchModal.PostcodeSearchModal, props));
|
|
46
|
+
});
|
|
47
|
+
return document.body;
|
|
48
|
+
}
|
|
49
|
+
/** matchMedia 를 vitest 환경에서 stub 한다 (jsdom 은 matches 를 항상 false 로 준다). */
|
|
50
|
+
function stubMatchMedia(matches) {
|
|
51
|
+
_vitest.vi.stubGlobal('matchMedia', query => ({
|
|
52
|
+
matches,
|
|
53
|
+
media: query,
|
|
54
|
+
onchange: null,
|
|
55
|
+
addEventListener: _vitest.vi.fn(),
|
|
56
|
+
removeEventListener: _vitest.vi.fn(),
|
|
57
|
+
addListener: _vitest.vi.fn(),
|
|
58
|
+
removeListener: _vitest.vi.fn(),
|
|
59
|
+
dispatchEvent: _vitest.vi.fn(() => false)
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* controlled input 에 값을 입력한다.
|
|
64
|
+
* React 는 element 의 value 프로퍼티를 가로채 변경을 추적하므로, 프로토타입의 네이티브 setter 를
|
|
65
|
+
* 직접 호출해야 React 가 "값이 바뀌었다"고 판단하고 onChange 를 발화한다.
|
|
66
|
+
*/
|
|
67
|
+
function setInputValue(input, value) {
|
|
68
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;
|
|
69
|
+
if (!nativeSetter) throw new Error('HTMLInputElement.value setter 를 찾을 수 없습니다');
|
|
70
|
+
(0, _testUtils.act)(() => {
|
|
71
|
+
nativeSetter.call(input, value);
|
|
72
|
+
input.dispatchEvent(new Event('input', {
|
|
73
|
+
bubbles: true
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function makeResults(count) {
|
|
78
|
+
return Array.from({
|
|
79
|
+
length: count
|
|
80
|
+
}, (_, i) => ({
|
|
81
|
+
zipCode: String(ZIP_CODE_BASE + i),
|
|
82
|
+
roadAddress: `경기 성남시 분당구 판교로 ${ROAD_NUMBER_BASE + i}`,
|
|
83
|
+
jibunAddress: `경기 성남시 분당구 삼평동 ${JIBUN_NUMBER_BASE + i}`
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
function baseProps() {
|
|
87
|
+
let overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
88
|
+
return {
|
|
89
|
+
open: true,
|
|
90
|
+
onClose: _vitest.vi.fn(),
|
|
91
|
+
searchQuery: '',
|
|
92
|
+
onSearchQueryChange: _vitest.vi.fn(),
|
|
93
|
+
onSearch: _vitest.vi.fn(),
|
|
94
|
+
results: [],
|
|
95
|
+
totalCount: 0,
|
|
96
|
+
currentPage: 1,
|
|
97
|
+
onPageChange: _vitest.vi.fn(),
|
|
98
|
+
onSelect: _vitest.vi.fn(),
|
|
99
|
+
...overrides
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const tipOf = el => el.querySelector('.ncua-postcode-search-modal__tip');
|
|
103
|
+
const searchAreaOf = el => el.querySelector('.ncua-postcode-search-modal__search-area');
|
|
104
|
+
const isFixedSearchArea = el => Boolean(searchAreaOf(el)?.classList.contains('is-fixed'));
|
|
105
|
+
const scrollerOf = el => el.querySelector('.ncua-modal__content');
|
|
106
|
+
/** jsdom 은 레이아웃이 없어 scrollTop 이 항상 0 이므로, 값을 덮어쓰고 scroll 이벤트를 쏜다. */
|
|
107
|
+
function scrollContent(el, scrollTop) {
|
|
108
|
+
const scroller = scrollerOf(el);
|
|
109
|
+
if (!scroller) throw new Error('모달 본문 스크롤 컨테이너를 찾을 수 없습니다');
|
|
110
|
+
Object.defineProperty(scroller, 'scrollTop', {
|
|
111
|
+
value: scrollTop,
|
|
112
|
+
configurable: true
|
|
113
|
+
});
|
|
114
|
+
(0, _testUtils.act)(() => {
|
|
115
|
+
scroller.dispatchEvent(new Event('scroll'));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const resultTitleOf = el => el.querySelector('.ncua-postcode-search-modal__result-title');
|
|
119
|
+
const resultDescOf = el => el.querySelector('.ncua-postcode-search-modal__result-desc');
|
|
120
|
+
const countLabelOf = el => el.querySelector('.ncua-postcode-search-modal__count');
|
|
121
|
+
const itemsOf = el => el.querySelectorAll('.ncua-postcode-search-modal__item');
|
|
122
|
+
const inputRootOf = el => el.querySelector('.ncua-input');
|
|
123
|
+
const hintOf = el => el.querySelector('.ncua-input__hint-text');
|
|
124
|
+
const emptyStateOf = el => el.querySelector('.ncua-empty-state');
|
|
125
|
+
const paginationOf = el => el.querySelector('.ncua-pagination');
|
|
126
|
+
(0, _vitest.beforeEach)(() => {
|
|
127
|
+
stubMatchMedia(false);
|
|
128
|
+
});
|
|
129
|
+
(0, _vitest.afterEach)(() => {
|
|
130
|
+
if (root && container) {
|
|
131
|
+
(0, _testUtils.act)(() => root?.unmount());
|
|
132
|
+
container.remove();
|
|
133
|
+
}
|
|
134
|
+
root = null;
|
|
135
|
+
container = null;
|
|
136
|
+
_vitest.vi.unstubAllGlobals();
|
|
137
|
+
});
|
|
138
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 1: 검색 전 초기 상태', () => {
|
|
139
|
+
(0, _vitest.it)('Tip 카드만 노출되고 카운트·리스트·페이지네이션·EmptyState 는 렌더되지 않는다', () => {
|
|
140
|
+
// Given: 검색어·결과가 비어 있고 에러도 없는 상태에서
|
|
141
|
+
// When: 모달을 열면
|
|
142
|
+
const el = render(baseProps());
|
|
143
|
+
// Then: Tip 카드만 노출되고 결과 영역은 전부 미노출이다
|
|
144
|
+
(0, _vitest.expect)(tipOf(el)).not.toBeNull();
|
|
145
|
+
(0, _vitest.expect)(resultTitleOf(el)).toBeNull();
|
|
146
|
+
(0, _vitest.expect)(countLabelOf(el)).toBeNull();
|
|
147
|
+
(0, _vitest.expect)(el.querySelector('.ncua-postcode-search-modal__list')).toBeNull();
|
|
148
|
+
(0, _vitest.expect)(paginationOf(el)).toBeNull();
|
|
149
|
+
(0, _vitest.expect)(emptyStateOf(el)).toBeNull();
|
|
150
|
+
});
|
|
151
|
+
(0, _vitest.it)('검색 인풋이 비어 있고 destructive 상태가 아니다', () => {
|
|
152
|
+
// Given/When: 초기 상태로 렌더하면
|
|
153
|
+
const el = render(baseProps());
|
|
154
|
+
// Then: 입력값이 비어 있고 오류 스타일이 아니다
|
|
155
|
+
const input = el.querySelector('.ncua-input input');
|
|
156
|
+
(0, _vitest.expect)(input?.value).toBe('');
|
|
157
|
+
(0, _vitest.expect)(inputRootOf(el)?.classList.contains('destructive')).toBe(false);
|
|
158
|
+
(0, _vitest.expect)(hintOf(el)).toBeNull();
|
|
159
|
+
});
|
|
160
|
+
(0, _vitest.it)('open=false 면 아무것도 렌더되지 않는다', () => {
|
|
161
|
+
// Given/When: 닫힌 상태로 렌더하면
|
|
162
|
+
const el = render(baseProps({
|
|
163
|
+
open: false
|
|
164
|
+
}));
|
|
165
|
+
// Then: 모달 자체가 없다
|
|
166
|
+
(0, _vitest.expect)(el.querySelector('.ncua-modal')).toBeNull();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 2~4: 에러코드별 hint 매핑', () => {
|
|
170
|
+
_vitest.it.each([['E0008', '서', '검색어를 두 글자 이상 입력해주세요.'], ['E0006', '서울특별시', '시도명으로는 검색이 불가합니다.'], ['E0011', '!!!', '검색어를 다시 입력해주세요.'], ['E0009', '!!!', '검색어를 다시 입력해주세요.'], ['E0010', '!!!', '검색어를 다시 입력해주세요.'], ['E0012', '!!!', '검색어를 다시 입력해주세요.'], ['E0013', '!!!', '검색어를 다시 입력해주세요.']])('%s 이면 destructive 와 hint "%s" 가 노출된다', (errorCode, searchQuery, hint) => {
|
|
171
|
+
// Given/When: 에러코드를 전달해 렌더하면
|
|
172
|
+
const el = render(baseProps({
|
|
173
|
+
searchQuery,
|
|
174
|
+
errorCode
|
|
175
|
+
}));
|
|
176
|
+
// Then: Input 이 destructive 이고 매핑된 hint 문구가 나온다
|
|
177
|
+
(0, _vitest.expect)(inputRootOf(el)?.classList.contains('destructive')).toBe(true);
|
|
178
|
+
(0, _vitest.expect)(hintOf(el)?.textContent).toBe(hint);
|
|
179
|
+
});
|
|
180
|
+
(0, _vitest.it)('에러 상태에서는 Tip 카드가 노출되고 리스트·EmptyState 는 미노출이다', () => {
|
|
181
|
+
// Given/When: 에러코드를 전달해 렌더하면
|
|
182
|
+
const el = render(baseProps({
|
|
183
|
+
searchQuery: '서',
|
|
184
|
+
errorCode: 'E0008'
|
|
185
|
+
}));
|
|
186
|
+
// Then: Tip 카드만 남는다
|
|
187
|
+
(0, _vitest.expect)(tipOf(el)).not.toBeNull();
|
|
188
|
+
(0, _vitest.expect)(resultTitleOf(el)).toBeNull();
|
|
189
|
+
(0, _vitest.expect)(el.querySelector('.ncua-postcode-search-modal__list')).toBeNull();
|
|
190
|
+
(0, _vitest.expect)(emptyStateOf(el)).toBeNull();
|
|
191
|
+
(0, _vitest.expect)(paginationOf(el)).toBeNull();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 5: 검색 결과 없음', () => {
|
|
195
|
+
(0, _vitest.it)('검색 실행 전 입력만 한 상태에서는 EmptyState 가 노출되지 않는다', () => {
|
|
196
|
+
// Given: 검색어가 빈 상태로 열려 있다가
|
|
197
|
+
render(baseProps({
|
|
198
|
+
searchQuery: '',
|
|
199
|
+
results: [],
|
|
200
|
+
totalCount: 0
|
|
201
|
+
}));
|
|
202
|
+
// When: 검색을 실행하지 않고 글자만 입력하면
|
|
203
|
+
const el = render(baseProps({
|
|
204
|
+
searchQuery: '존재하지않는주소',
|
|
205
|
+
results: [],
|
|
206
|
+
totalCount: 0
|
|
207
|
+
}));
|
|
208
|
+
// Then: "검색 결과가 없습니다." 는 뜨지 않고 Tip 카드만 유지된다
|
|
209
|
+
(0, _vitest.expect)(emptyStateOf(el)).toBeNull();
|
|
210
|
+
(0, _vitest.expect)(tipOf(el)).not.toBeNull();
|
|
211
|
+
});
|
|
212
|
+
(0, _vitest.it)('EmptyState 가 "검색 결과가 없습니다." 로 렌더되고 Tip 카드가 유지된다', () => {
|
|
213
|
+
// Given: 검색어는 있으나 결과가 0건인 상태에서
|
|
214
|
+
const el = render(baseProps({
|
|
215
|
+
searchQuery: '존재하지않는주소',
|
|
216
|
+
results: [],
|
|
217
|
+
totalCount: 0
|
|
218
|
+
}));
|
|
219
|
+
// When: 검색 버튼을 눌러 실제로 검색을 실행하면
|
|
220
|
+
(0, _testUtils.act)(() => {
|
|
221
|
+
el.querySelector('.ncua-postcode-search-modal__search-button')?.click();
|
|
222
|
+
});
|
|
223
|
+
// Then: EmptyState 가 노출되고 오류 스타일은 아니며 페이지네이션은 없다
|
|
224
|
+
(0, _vitest.expect)(emptyStateOf(el)?.textContent).toContain('검색 결과가 없습니다.');
|
|
225
|
+
(0, _vitest.expect)(tipOf(el)).not.toBeNull();
|
|
226
|
+
(0, _vitest.expect)(resultTitleOf(el)).toBeNull();
|
|
227
|
+
(0, _vitest.expect)(inputRootOf(el)?.classList.contains('destructive')).toBe(false);
|
|
228
|
+
(0, _vitest.expect)(paginationOf(el)).toBeNull();
|
|
229
|
+
(0, _vitest.expect)(countLabelOf(el)).toBeNull();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 6: 결과 있음', () => {
|
|
233
|
+
(0, _vitest.it)('카운트 "검색 5개" 와 5행 리스트가 렌더되고 Tip 카드는 미노출된다', () => {
|
|
234
|
+
// Given/When: 5건 결과를 전달하면
|
|
235
|
+
const results = makeResults(SMALL_RESULT_COUNT);
|
|
236
|
+
const el = render(baseProps({
|
|
237
|
+
searchQuery: '판교로',
|
|
238
|
+
results,
|
|
239
|
+
totalCount: SMALL_RESULT_COUNT
|
|
240
|
+
}));
|
|
241
|
+
// Then: 카운트·리스트가 노출되고 Tip 카드는 사라진다
|
|
242
|
+
(0, _vitest.expect)(countLabelOf(el)?.textContent).toBe(`검색 ${SMALL_RESULT_COUNT}개`);
|
|
243
|
+
(0, _vitest.expect)(itemsOf(el)).toHaveLength(SMALL_RESULT_COUNT);
|
|
244
|
+
(0, _vitest.expect)(tipOf(el)).toBeNull();
|
|
245
|
+
});
|
|
246
|
+
(0, _vitest.it)('각 행에 라디오·도로명·우편번호·지번이 모두 렌더된다', () => {
|
|
247
|
+
// Given/When: 5건 결과를 전달하면
|
|
248
|
+
const results = makeResults(SMALL_RESULT_COUNT);
|
|
249
|
+
const el = render(baseProps({
|
|
250
|
+
searchQuery: '판교로',
|
|
251
|
+
results,
|
|
252
|
+
totalCount: SMALL_RESULT_COUNT
|
|
253
|
+
}));
|
|
254
|
+
// Then: 첫 행의 구성요소가 설계대로 존재한다
|
|
255
|
+
const first = itemsOf(el)[0];
|
|
256
|
+
(0, _vitest.expect)(first.querySelector('input[type="radio"]')).not.toBeNull();
|
|
257
|
+
(0, _vitest.expect)(first.querySelector('.ncua-postcode-search-modal__item-road')?.textContent).toBe(results[0].roadAddress);
|
|
258
|
+
(0, _vitest.expect)(first.querySelector('.ncua-postcode-search-modal__item-zip')?.textContent).toBe(results[0].zipCode);
|
|
259
|
+
(0, _vitest.expect)(first.querySelector('.ncua-postcode-search-modal__item-jibun')?.textContent).toBe(results[0].jibunAddress);
|
|
260
|
+
// 도로명·지번 두 줄과 각 줄의 배지
|
|
261
|
+
(0, _vitest.expect)(first.querySelectorAll('.ncua-postcode-search-modal__addr-line')).toHaveLength(2);
|
|
262
|
+
(0, _vitest.expect)(first.querySelectorAll('.ncua-postcode-search-modal__badge')).toHaveLength(2);
|
|
263
|
+
});
|
|
264
|
+
(0, _vitest.it)('totalPage=1 이면 점프 버튼 없이 페이지 번호만 노출된다', () => {
|
|
265
|
+
// Given/When: 5건(1페이지) 결과를 전달하면
|
|
266
|
+
const el = render(baseProps({
|
|
267
|
+
searchQuery: '판교로',
|
|
268
|
+
results: makeResults(SMALL_RESULT_COUNT),
|
|
269
|
+
totalCount: SMALL_RESULT_COUNT
|
|
270
|
+
}));
|
|
271
|
+
// Then: 점프 버튼이 없다
|
|
272
|
+
(0, _vitest.expect)(paginationOf(el)).not.toBeNull();
|
|
273
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__first')).toBeNull();
|
|
274
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__last')).toBeNull();
|
|
275
|
+
(0, _vitest.expect)(el.querySelectorAll('.ncua-pagination__page-num')).toHaveLength(SMALL_RESULT_TOTAL_PAGE);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 7: 결과 여러 페이지', () => {
|
|
279
|
+
(0, _vitest.it)('카운트 "검색 45개" 와 15행 리스트가 렌더되고 Tip 카드 대신 결과 안내 문구가 남는다', () => {
|
|
280
|
+
// Given/When: 45건 중 첫 페이지 15건을 전달하면
|
|
281
|
+
const el = render(baseProps({
|
|
282
|
+
searchQuery: '판교로',
|
|
283
|
+
results: makeResults(PAGE_SIZE),
|
|
284
|
+
totalCount: LARGE_RESULT_COUNT
|
|
285
|
+
}));
|
|
286
|
+
// Then: Tip 카드는 사라지고 검색 영역의 안내 문구(제목·조합)가 남는다
|
|
287
|
+
(0, _vitest.expect)(countLabelOf(el)?.textContent).toBe(`검색 ${LARGE_RESULT_COUNT}개`);
|
|
288
|
+
(0, _vitest.expect)(itemsOf(el)).toHaveLength(PAGE_SIZE);
|
|
289
|
+
(0, _vitest.expect)(tipOf(el)).toBeNull();
|
|
290
|
+
(0, _vitest.expect)(resultTitleOf(el)?.textContent).toBe('아래 조합으로 검색하면 원하는 주소를 더 쉽게 찾을 수 있어요.');
|
|
291
|
+
(0, _vitest.expect)(resultDescOf(el)?.textContent).toBe('도로명+건물번호, 지역명+지번, 지역명+건물명(아파트명)');
|
|
292
|
+
});
|
|
293
|
+
(0, _vitest.it)('검색 인풋과 안내 문구가 같은 고정 영역 안에 묶이고 결과 목록은 그 밖에 있다', () => {
|
|
294
|
+
// Given/When: 결과가 여러 페이지인 상태로 렌더하면
|
|
295
|
+
const el = render(baseProps({
|
|
296
|
+
searchQuery: '판교로',
|
|
297
|
+
results: makeResults(PAGE_SIZE),
|
|
298
|
+
totalCount: LARGE_RESULT_COUNT
|
|
299
|
+
}));
|
|
300
|
+
// Then: 상단 고정 영역이 인풋 행과 안내 문구를 함께 감싸고, 스크롤되는 목록은 밖에 남는다
|
|
301
|
+
const searchArea = searchAreaOf(el);
|
|
302
|
+
(0, _vitest.expect)(searchArea?.querySelector('.ncua-postcode-search-modal__search')).not.toBeNull();
|
|
303
|
+
(0, _vitest.expect)(searchArea?.querySelector('.ncua-postcode-search-modal__result-title')).not.toBeNull();
|
|
304
|
+
(0, _vitest.expect)(searchArea?.querySelector('.ncua-postcode-search-modal__result-desc')).not.toBeNull();
|
|
305
|
+
(0, _vitest.expect)(searchArea?.querySelector('.ncua-postcode-search-modal__list')).toBeNull();
|
|
306
|
+
});
|
|
307
|
+
(0, _vitest.it)('totalPage(3) 가 PAGER_WINDOW(10) 이하이므로 점프 버튼은 노출되지 않는다', () => {
|
|
308
|
+
// Given/When: totalCount=45, PAGE_SIZE=15 → totalPage=3
|
|
309
|
+
const el = render(baseProps({
|
|
310
|
+
searchQuery: '판교로',
|
|
311
|
+
results: makeResults(PAGE_SIZE),
|
|
312
|
+
totalCount: LARGE_RESULT_COUNT
|
|
313
|
+
}));
|
|
314
|
+
// Then: 페이지 번호 3개만 노출된다
|
|
315
|
+
(0, _vitest.expect)(el.querySelectorAll('.ncua-pagination__page-num')).toHaveLength(LARGE_RESULT_TOTAL_PAGE);
|
|
316
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__first')).toBeNull();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
(0, _vitest.describe)('PostcodeSearchModal — Case 8: 결과 대량', () => {
|
|
320
|
+
(0, _vitest.it)('totalCount=200 이면 첫/이전/다음/마지막 점프 버튼이 노출된다', () => {
|
|
321
|
+
// Given/When: totalCount=200 → totalPage=14 > PAGER_WINDOW(10)
|
|
322
|
+
const el = render(baseProps({
|
|
323
|
+
searchQuery: '판교로',
|
|
324
|
+
results: makeResults(PAGE_SIZE),
|
|
325
|
+
totalCount: HUGE_RESULT_COUNT
|
|
326
|
+
}));
|
|
327
|
+
// Then: 점프 버튼 4종이 모두 존재한다
|
|
328
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__first')).not.toBeNull();
|
|
329
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__before')).not.toBeNull();
|
|
330
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__next')).not.toBeNull();
|
|
331
|
+
(0, _vitest.expect)(el.querySelector('.ncua-pagination__last')).not.toBeNull();
|
|
332
|
+
(0, _vitest.expect)(tipOf(el)).toBeNull();
|
|
333
|
+
(0, _vitest.expect)(resultTitleOf(el)).not.toBeNull();
|
|
334
|
+
});
|
|
335
|
+
(0, _vitest.it)('3페이지 버튼을 클릭하면 onPageChange(3) 이 호출된다', () => {
|
|
336
|
+
// Given: 대량 결과가 렌더된 상태에서
|
|
337
|
+
const onPageChange = _vitest.vi.fn();
|
|
338
|
+
const el = render(baseProps({
|
|
339
|
+
searchQuery: '판교로',
|
|
340
|
+
results: makeResults(PAGE_SIZE),
|
|
341
|
+
totalCount: HUGE_RESULT_COUNT,
|
|
342
|
+
onPageChange
|
|
343
|
+
}));
|
|
344
|
+
// When: 3번 페이지 버튼을 클릭하면
|
|
345
|
+
const pageButtons = el.querySelectorAll('.ncua-pagination__page-num');
|
|
346
|
+
(0, _testUtils.act)(() => {
|
|
347
|
+
pageButtons[TARGET_PAGE - 1]?.click();
|
|
348
|
+
});
|
|
349
|
+
// Then: 3 이 전달된다
|
|
350
|
+
(0, _vitest.expect)(onPageChange).toHaveBeenCalledWith(TARGET_PAGE);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
(0, _vitest.describe)('PostcodeSearchModal — 아이템 선택', () => {
|
|
354
|
+
(0, _vitest.it)('라디오를 클릭하면 해당 결과로 onSelect 가 호출된다', () => {
|
|
355
|
+
// Given: 5건 결과가 렌더된 상태에서
|
|
356
|
+
const results = makeResults(SMALL_RESULT_COUNT);
|
|
357
|
+
const onSelect = _vitest.vi.fn();
|
|
358
|
+
const el = render(baseProps({
|
|
359
|
+
searchQuery: '판교로',
|
|
360
|
+
results,
|
|
361
|
+
totalCount: SMALL_RESULT_COUNT,
|
|
362
|
+
onSelect
|
|
363
|
+
}));
|
|
364
|
+
// When: 2번째 아이템의 라디오를 클릭하면
|
|
365
|
+
const radios = el.querySelectorAll('.ncua-postcode-search-modal__item input[type="radio"]');
|
|
366
|
+
(0, _testUtils.act)(() => {
|
|
367
|
+
radios[1]?.click();
|
|
368
|
+
});
|
|
369
|
+
// Then: 2번째 결과 객체가 전달된다
|
|
370
|
+
(0, _vitest.expect)(onSelect).toHaveBeenCalledWith(results[1]);
|
|
371
|
+
});
|
|
372
|
+
(0, _vitest.it)('loading 중에는 결과가 0건이어도 EmptyState 가 뜨지 않는다', () => {
|
|
373
|
+
// Given: 검색을 실행해 EmptyState 가 떠 있는 상태에서
|
|
374
|
+
render(baseProps({
|
|
375
|
+
searchQuery: '판교로',
|
|
376
|
+
results: [],
|
|
377
|
+
totalCount: 0
|
|
378
|
+
}));
|
|
379
|
+
(0, _testUtils.act)(() => {
|
|
380
|
+
document.body.querySelector('.ncua-postcode-search-modal__search-button')?.click();
|
|
381
|
+
});
|
|
382
|
+
// When: 사용처가 API 응답을 기다린다고 알리면
|
|
383
|
+
const el = render(baseProps({
|
|
384
|
+
searchQuery: '판교로',
|
|
385
|
+
results: [],
|
|
386
|
+
totalCount: 0,
|
|
387
|
+
loading: true
|
|
388
|
+
}));
|
|
389
|
+
// Then: "검색 결과가 없습니다." 는 노출되지 않는다
|
|
390
|
+
(0, _vitest.expect)(emptyStateOf(el)).toBeNull();
|
|
391
|
+
});
|
|
392
|
+
(0, _vitest.it)('모달을 다시 열면 이전 선택과 검색 상태가 초기화된다', () => {
|
|
393
|
+
// Given: 결과에서 한 행을 고른 뒤
|
|
394
|
+
const results = makeResults(SMALL_RESULT_COUNT);
|
|
395
|
+
const el = render(baseProps({
|
|
396
|
+
searchQuery: '판교로',
|
|
397
|
+
results,
|
|
398
|
+
totalCount: SMALL_RESULT_COUNT
|
|
399
|
+
}));
|
|
400
|
+
const radios = el.querySelectorAll('.ncua-postcode-search-modal__item input[type="radio"]');
|
|
401
|
+
(0, _testUtils.act)(() => {
|
|
402
|
+
radios[1]?.click();
|
|
403
|
+
});
|
|
404
|
+
(0, _vitest.expect)(radios[1].checked).toBe(true);
|
|
405
|
+
// When: 모달을 닫았다가 다시 열면
|
|
406
|
+
render(baseProps({
|
|
407
|
+
open: false,
|
|
408
|
+
searchQuery: '판교로',
|
|
409
|
+
results,
|
|
410
|
+
totalCount: SMALL_RESULT_COUNT
|
|
411
|
+
}));
|
|
412
|
+
const reopened = render(baseProps({
|
|
413
|
+
searchQuery: '판교로',
|
|
414
|
+
results,
|
|
415
|
+
totalCount: SMALL_RESULT_COUNT
|
|
416
|
+
}));
|
|
417
|
+
// Then: 선택 표시가 남아 있지 않다
|
|
418
|
+
const reopenedRadios = reopened.querySelectorAll('.ncua-postcode-search-modal__item input[type="radio"]');
|
|
419
|
+
(0, _vitest.expect)(reopenedRadios[1].checked).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
(0, _vitest.it)('클릭한 행만 checked 로 표시된다 — 사용처가 값을 되돌려주지 않아도 된다', () => {
|
|
422
|
+
// Given: 결과 5건이 렌더된 상태에서
|
|
423
|
+
const results = makeResults(SMALL_RESULT_COUNT);
|
|
424
|
+
const el = render(baseProps({
|
|
425
|
+
searchQuery: '판교로',
|
|
426
|
+
results,
|
|
427
|
+
totalCount: SMALL_RESULT_COUNT
|
|
428
|
+
}));
|
|
429
|
+
const radios = el.querySelectorAll('.ncua-postcode-search-modal__item input[type="radio"]');
|
|
430
|
+
// When: 두 번째 행을 클릭하면
|
|
431
|
+
(0, _testUtils.act)(() => {
|
|
432
|
+
radios[1]?.click();
|
|
433
|
+
});
|
|
434
|
+
// Then: 그 행만 checked 다
|
|
435
|
+
(0, _vitest.expect)(radios[0].checked).toBe(false);
|
|
436
|
+
(0, _vitest.expect)(radios[1].checked).toBe(true);
|
|
437
|
+
(0, _vitest.expect)(radios[2].checked).toBe(false);
|
|
438
|
+
});
|
|
439
|
+
(0, _vitest.it)('우편번호가 같은 행이 있어도 클릭한 행만 checked 다', () => {
|
|
440
|
+
// Given: 같은 우편번호를 쓰는 두 행이 한 페이지에 있을 때
|
|
441
|
+
const sameZip = '13529';
|
|
442
|
+
const results = [{
|
|
443
|
+
zipCode: sameZip,
|
|
444
|
+
roadAddress: '경기 성남시 분당구 판교로 242',
|
|
445
|
+
jibunAddress: '경기 성남시 분당구 삼평동 620'
|
|
446
|
+
}, {
|
|
447
|
+
zipCode: sameZip,
|
|
448
|
+
roadAddress: '경기 성남시 분당구 판교로 242',
|
|
449
|
+
jibunAddress: '경기 성남시 분당구 삼평동 621'
|
|
450
|
+
}];
|
|
451
|
+
const el = render(baseProps({
|
|
452
|
+
searchQuery: '판교로',
|
|
453
|
+
results,
|
|
454
|
+
totalCount: results.length
|
|
455
|
+
}));
|
|
456
|
+
const radios = el.querySelectorAll('.ncua-postcode-search-modal__item input[type="radio"]');
|
|
457
|
+
// When: 두 번째 행을 클릭하면
|
|
458
|
+
(0, _testUtils.act)(() => {
|
|
459
|
+
radios[1]?.click();
|
|
460
|
+
});
|
|
461
|
+
// Then: 첫 행은 선택되지 않는다
|
|
462
|
+
(0, _vitest.expect)(radios[0].checked).toBe(false);
|
|
463
|
+
(0, _vitest.expect)(radios[1].checked).toBe(true);
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
(0, _vitest.describe)('PostcodeSearchModal — 검색 인터랙션', () => {
|
|
467
|
+
(0, _vitest.it)('검색 버튼을 누르면 onSearch 가 호출된다', () => {
|
|
468
|
+
// Given: 검색어가 입력된 상태에서
|
|
469
|
+
const onSearch = _vitest.vi.fn();
|
|
470
|
+
const el = render(baseProps({
|
|
471
|
+
searchQuery: '판교로',
|
|
472
|
+
onSearch
|
|
473
|
+
}));
|
|
474
|
+
// When: 인풋 바깥 오른쪽의 검색 버튼을 클릭하면
|
|
475
|
+
const searchButton = el.querySelector('.ncua-postcode-search-modal__search-button');
|
|
476
|
+
(0, _vitest.expect)(searchButton?.textContent).toBe('검색');
|
|
477
|
+
(0, _testUtils.act)(() => {
|
|
478
|
+
searchButton?.click();
|
|
479
|
+
});
|
|
480
|
+
// Then: onSearch 가 호출된다
|
|
481
|
+
(0, _vitest.expect)(onSearch).toHaveBeenCalledTimes(1);
|
|
482
|
+
});
|
|
483
|
+
(0, _vitest.it)('Enter 를 누르면 onSearch 가 호출된다', () => {
|
|
484
|
+
// Given: 검색어가 입력된 상태에서
|
|
485
|
+
const onSearch = _vitest.vi.fn();
|
|
486
|
+
const el = render(baseProps({
|
|
487
|
+
searchQuery: '판교로',
|
|
488
|
+
onSearch
|
|
489
|
+
}));
|
|
490
|
+
const input = el.querySelector('.ncua-input input');
|
|
491
|
+
if (!input) throw new Error('검색 인풋이 렌더되지 않았습니다');
|
|
492
|
+
// When: 인풋에서 Enter 를 누르면
|
|
493
|
+
(0, _testUtils.act)(() => {
|
|
494
|
+
input.dispatchEvent(new KeyboardEvent('keydown', {
|
|
495
|
+
key: 'Enter',
|
|
496
|
+
bubbles: true
|
|
497
|
+
}));
|
|
498
|
+
});
|
|
499
|
+
// Then: 검색 버튼을 누른 것과 동일하게 onSearch 가 호출된다
|
|
500
|
+
(0, _vitest.expect)(onSearch).toHaveBeenCalledTimes(1);
|
|
501
|
+
});
|
|
502
|
+
(0, _vitest.it)('한글 조합 중 Enter 는 검색으로 보지 않는다', () => {
|
|
503
|
+
// Given: 검색어를 조합 중인 상태에서
|
|
504
|
+
const onSearch = _vitest.vi.fn();
|
|
505
|
+
const el = render(baseProps({
|
|
506
|
+
searchQuery: '판교',
|
|
507
|
+
onSearch
|
|
508
|
+
}));
|
|
509
|
+
const input = el.querySelector('.ncua-input input');
|
|
510
|
+
if (!input) throw new Error('검색 인풋이 렌더되지 않았습니다');
|
|
511
|
+
// When: 조합 확정용 Enter 가 들어오면
|
|
512
|
+
(0, _testUtils.act)(() => {
|
|
513
|
+
input.dispatchEvent(new KeyboardEvent('keydown', {
|
|
514
|
+
key: 'Enter',
|
|
515
|
+
isComposing: true,
|
|
516
|
+
bubbles: true
|
|
517
|
+
}));
|
|
518
|
+
});
|
|
519
|
+
// Then: 검색은 실행되지 않는다
|
|
520
|
+
(0, _vitest.expect)(onSearch).not.toHaveBeenCalled();
|
|
521
|
+
});
|
|
522
|
+
(0, _vitest.it)('입력값이 바뀌면 onSearchQueryChange 에 새 값이 전달된다', () => {
|
|
523
|
+
// Given: controlled 인풋이 렌더된 상태에서
|
|
524
|
+
const onSearchQueryChange = _vitest.vi.fn();
|
|
525
|
+
const el = render(baseProps({
|
|
526
|
+
onSearchQueryChange
|
|
527
|
+
}));
|
|
528
|
+
// When: 값을 입력하면
|
|
529
|
+
const input = el.querySelector('.ncua-input input');
|
|
530
|
+
if (!input) throw new Error('검색 인풋이 렌더되지 않았습니다');
|
|
531
|
+
// controlled input 은 React 의 value tracker 를 거치므로, 네이티브 setter 로 값을 넣어야
|
|
532
|
+
// React 가 변경을 감지해 onChange 를 발화한다.
|
|
533
|
+
setInputValue(input, '판교로');
|
|
534
|
+
// Then: 새 값이 전달된다
|
|
535
|
+
(0, _vitest.expect)(onSearchQueryChange).toHaveBeenCalledWith('판교로');
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
(0, _vitest.describe)('PostcodeSearchModal — 반응형 전환', () => {
|
|
539
|
+
(0, _vitest.it)('데스크톱(768px 초과) 에서는 Pagination 이 pc 모드로 렌더된다', () => {
|
|
540
|
+
// Given/When: matchMedia 가 매치되지 않는 환경에서 렌더하면
|
|
541
|
+
stubMatchMedia(false);
|
|
542
|
+
const el = render(baseProps({
|
|
543
|
+
searchQuery: '판교로',
|
|
544
|
+
results: makeResults(SMALL_RESULT_COUNT),
|
|
545
|
+
totalCount: SMALL_RESULT_COUNT
|
|
546
|
+
}));
|
|
547
|
+
// Then: pc 모디파이어가 붙는다
|
|
548
|
+
(0, _vitest.expect)(paginationOf(el)?.classList.contains('ncua-pagination--pc')).toBe(true);
|
|
549
|
+
});
|
|
550
|
+
(0, _vitest.it)('모바일(768px 이하) 에서는 Pagination 이 mo 모드로 렌더된다', () => {
|
|
551
|
+
// Given/When: 640px 상당으로 matchMedia 가 매치되는 환경에서 렌더하면
|
|
552
|
+
stubMatchMedia(true);
|
|
553
|
+
const el = render(baseProps({
|
|
554
|
+
searchQuery: '판교로',
|
|
555
|
+
results: makeResults(SMALL_RESULT_COUNT),
|
|
556
|
+
totalCount: SMALL_RESULT_COUNT
|
|
557
|
+
}));
|
|
558
|
+
// Then: mo 모디파이어가 붙는다
|
|
559
|
+
(0, _vitest.expect)(paginationOf(el)?.classList.contains('ncua-pagination--mo')).toBe(true);
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
(0, _vitest.describe)('PostcodeSearchModal.Tip — 서브컴포넌트', () => {
|
|
563
|
+
(0, _vitest.it)('조합 3종과 예시 주소를 모두 보여준다', () => {
|
|
564
|
+
// Given/When: Tip 카드가 노출되는 초기 상태로 렌더하면
|
|
565
|
+
const el = render(baseProps());
|
|
566
|
+
// Then: 안내 문구와 3개 조합, 예시 주소가 모두 포함된다
|
|
567
|
+
const tipText = tipOf(el)?.textContent ?? '';
|
|
568
|
+
(0, _vitest.expect)(tipText).toContain('아래 조합으로 검색하면 원하는 주소를 더 쉽게 찾을 수 있어요.');
|
|
569
|
+
(0, _vitest.expect)(tipText).toContain('도로명 + 건물번호');
|
|
570
|
+
(0, _vitest.expect)(tipText).toContain('예) 디지털로26길 43');
|
|
571
|
+
(0, _vitest.expect)(tipText).toContain('지역명(동·리) + 번지');
|
|
572
|
+
(0, _vitest.expect)(tipText).toContain('예) 구로동 235-3');
|
|
573
|
+
(0, _vitest.expect)(tipText).toContain('지역명(동·리) + 건물명(아파트명)');
|
|
574
|
+
(0, _vitest.expect)(tipText).toContain('예) 구로동 대륭포스트타워8차');
|
|
575
|
+
});
|
|
576
|
+
(0, _vitest.it)('Tip 아이콘은 하드코딩 SVG 가 아니라 아이콘 슬롯 클래스로 렌더된다', () => {
|
|
577
|
+
// Given/When: Tip 카드를 렌더하면
|
|
578
|
+
const el = render(baseProps());
|
|
579
|
+
// Then: 지정한 아이콘 클래스를 가진 svg 가 존재한다
|
|
580
|
+
(0, _vitest.expect)(tipOf(el)?.querySelector('svg.ncua-postcode-search-modal__tip-icon')).not.toBeNull();
|
|
581
|
+
});
|
|
582
|
+
(0, _vitest.it)('PostcodeSearchModal.Tip 이 compound 서브컴포넌트로 노출된다', () => {
|
|
583
|
+
// Given/When/Then: displayName 규약을 만족한다
|
|
584
|
+
(0, _vitest.expect)(typeof _PostcodeSearchModal.PostcodeSearchModal.Tip).toBe('function');
|
|
585
|
+
(0, _vitest.expect)(_PostcodeSearchModal.PostcodeSearchModal.Tip.displayName).toBe('PostcodeSearchModal.Tip');
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
(0, _vitest.describe)('PostcodeSearchModal — 검색 영역 고정 표시', () => {
|
|
589
|
+
(0, _vitest.it)('결과가 있어도 스크롤하기 전에는 is-fixed 가 붙지 않는다', () => {
|
|
590
|
+
// Given/When: 결과를 스크롤하지 않은 상태로 렌더하면
|
|
591
|
+
const el = render(baseProps({
|
|
592
|
+
searchQuery: '판교로',
|
|
593
|
+
results: makeResults(PAGE_SIZE),
|
|
594
|
+
totalCount: LARGE_RESULT_COUNT
|
|
595
|
+
}));
|
|
596
|
+
// Then: 검색 영역이 아직 떠 있지 않으므로 경계선 클래스도 없다
|
|
597
|
+
(0, _vitest.expect)(isFixedSearchArea(el)).toBe(false);
|
|
598
|
+
});
|
|
599
|
+
(0, _vitest.it)('결과를 스크롤하면 is-fixed 가 붙고, 맨 위로 돌아오면 다시 사라진다', () => {
|
|
600
|
+
// Given: 결과가 렌더된 상태에서
|
|
601
|
+
const el = render(baseProps({
|
|
602
|
+
searchQuery: '판교로',
|
|
603
|
+
results: makeResults(PAGE_SIZE),
|
|
604
|
+
totalCount: LARGE_RESULT_COUNT
|
|
605
|
+
}));
|
|
606
|
+
// When: 본문을 아래로 스크롤하면
|
|
607
|
+
scrollContent(el, SCROLLED_OFFSET);
|
|
608
|
+
// Then: 경계선 클래스가 붙는다
|
|
609
|
+
(0, _vitest.expect)(isFixedSearchArea(el)).toBe(true);
|
|
610
|
+
// When: 다시 맨 위로 올리면
|
|
611
|
+
scrollContent(el, SCROLL_TOP);
|
|
612
|
+
// Then: 경계선 클래스가 사라진다
|
|
613
|
+
(0, _vitest.expect)(isFixedSearchArea(el)).toBe(false);
|
|
614
|
+
});
|
|
615
|
+
(0, _vitest.it)('결과가 없으면 스크롤이 일어나도 is-fixed 가 붙지 않는다', () => {
|
|
616
|
+
// Given: 초기 상태(결과 없음)로 렌더하고
|
|
617
|
+
const el = render(baseProps());
|
|
618
|
+
// When: 본문 스크롤 이벤트가 들어와도
|
|
619
|
+
scrollContent(el, SCROLLED_OFFSET);
|
|
620
|
+
// Then: 고정할 대상이 없으므로 클래스는 붙지 않는다
|
|
621
|
+
(0, _vitest.expect)(isFixedSearchArea(el)).toBe(false);
|
|
622
|
+
});
|
|
623
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _PostcodeSearchModal = require("./PostcodeSearchModal");
|
|
7
|
+
Object.keys(_PostcodeSearchModal).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _PostcodeSearchModal[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _PostcodeSearchModal[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|