1
+ import { fireEvent , render , screen , waitFor } from "@testing-library/react"
2
+ import "@testing-library/jest-dom"
3
+ import ProductListPage from "@/pages/sample/product/list" ;
4
+ import mockRouter from "next-router-mock" ;
5
+ import { when } from "jest-when" ;
6
+ import { useProducts } from "@/client/sample/product" ;
7
+ import dayjs from "dayjs" ;
8
+
9
+ jest . mock ( "@/client/sample/product" ) ;
10
+
11
+ describe ( "테이블 랜더링" , ( ) => {
12
+ it ( "URL 파라메터가 없으면 1페이지에 해당하는 아이템을 5개씩 테이블에 보여준다" , async ( ) => {
13
+ // given
14
+ when ( useProducts as jest . Mock ) . calledWith ( {
15
+ page : 1
16
+ } ) . mockReturnValue ( {
17
+ data : {
18
+ data : {
19
+ page : {
20
+ currentPage : 1 ,
21
+ pageSize : 5 ,
22
+ totalPage : 1 ,
23
+ totalCount : 6
24
+ } ,
25
+ items : [
26
+ {
27
+ id : 1 ,
28
+ code : "A0001" ,
29
+ brand : "apple" ,
30
+ name : "iPhone 14 Pro" ,
31
+ price : 1550000 ,
32
+ status : "SALE" ,
33
+ createdAt : "2023-02-02T10:00:00+09:00" ,
34
+ updatedAt : "2023-02-02T10:00:00+09:00" ,
35
+ } ,
36
+ {
37
+ id : 2 ,
38
+ code : "A0002" ,
39
+ brand : "파타고니아" ,
40
+ name : "클래식 레트로-X 후리스 플리스 자켓" ,
41
+ price : 230000 ,
42
+ status : "SALE" ,
43
+ createdAt : "2023-02-02T11:00:00+09:00" ,
44
+ updatedAt : "2023-02-02T11:00:00+09:00" ,
45
+ } ,
46
+ {
47
+ id : 3 ,
48
+ code : "A0003" ,
49
+ brand : "다이슨" ,
50
+ name : "dyson v15 detect complete" ,
51
+ price : 1290000 ,
52
+ status : "SOLDOUT" ,
53
+ createdAt : "2023-02-02T12:00:00+09:00" ,
54
+ updatedAt : "2023-02-02T12:00:00+09:00" ,
55
+ } ,
56
+ {
57
+ id : 4 ,
58
+ code : "A0004" ,
59
+ brand : "Aēsop" ,
60
+ name : "레저렉션 아로마틱 핸드 워시" ,
61
+ price : 47000 ,
62
+ status : "NOTSALE" ,
63
+ createdAt : "2023-02-02T13:00:00+09:00" ,
64
+ updatedAt : "2023-02-02T13:00:00+09:00" ,
65
+ } ,
66
+ {
67
+ id : 5 ,
68
+ code : "A0005" ,
69
+ brand : "LUSH" ,
70
+ name : "더티 보디 스프레이" ,
71
+ price : 60000 ,
72
+ status : "SALE" ,
73
+ createdAt : "2023-02-02T14:00:00+09:00" ,
74
+ updatedAt : "2023-02-02T14:00:00+09:00" ,
75
+ } ,
76
+ ]
77
+ }
78
+ }
79
+ } ) ;
80
+
81
+ // when
82
+ await mockRouter . push ( "/sample/product/list" ) ;
83
+ render ( < ProductListPage /> )
84
+ await waitFor ( ( ) => screen . getByTestId ( "product-table" ) ) ;
85
+
86
+ // then
87
+ const productTable = screen . getByTestId ( "product-table" ) ;
88
+ expect ( productTable ) . toBeInTheDocument ( ) ;
89
+
90
+ // 테이블 헤더 확인
91
+ const tableHeader = productTable . querySelector ( "thead > tr" ) ;
92
+ expect ( tableHeader ) . not . toBeNull ( ) ;
93
+ const headerColumns = ( tableHeader as Element ) . querySelectorAll ( "th" ) ;
94
+ expect ( headerColumns ) . toHaveLength ( 7 ) ;
95
+ expect ( headerColumns [ 0 ] ) . toHaveTextContent ( "" ) ;
96
+ expect ( headerColumns [ 1 ] ) . toHaveTextContent ( "상품코드" ) ;
97
+ expect ( headerColumns [ 2 ] ) . toHaveTextContent ( "상품명" ) ;
98
+ expect ( headerColumns [ 3 ] ) . toHaveTextContent ( "금액" ) ;
99
+ expect ( headerColumns [ 4 ] ) . toHaveTextContent ( "판매상태" ) ;
100
+ expect ( headerColumns [ 5 ] ) . toHaveTextContent ( "생성일시" ) ;
101
+ expect ( headerColumns [ 6 ] ) . toHaveTextContent ( "수정일시" ) ;
102
+
103
+ // 테이블 바디 확인
104
+ const tableBodyRows = productTable . querySelectorAll ( "tbody > tr" ) ;
105
+ expect ( tableBodyRows ) . toHaveLength ( 6 ) ; // ant table은 컨텐츠이 담기지 않는 TR이 하나 존재하기 때문에 컨텐츠 + 1를 확인한다.
106
+
107
+ const bodyRow1Columns = tableBodyRows [ 1 ] . querySelectorAll ( "td" ) ;
108
+ expect ( bodyRow1Columns ) . toHaveLength ( 8 ) ;
109
+ expect ( bodyRow1Columns [ 2 ] ) . toHaveTextContent ( "A0001" ) ;
110
+ expect ( bodyRow1Columns [ 3 ] ) . toHaveTextContent ( "appleiPhone 14 Pro" ) ;
111
+ expect ( bodyRow1Columns [ 4 ] ) . toHaveTextContent ( "1,550,000원" ) ;
112
+ expect ( bodyRow1Columns [ 5 ] ) . toHaveTextContent ( "SALE" ) ;
113
+ expect ( bodyRow1Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0210:00" ) ;
114
+ expect ( bodyRow1Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0210:00" ) ;
115
+
116
+ const bodyRow2Columns = tableBodyRows [ 2 ] . querySelectorAll ( "td" ) ;
117
+ expect ( bodyRow2Columns ) . toHaveLength ( 8 ) ;
118
+ expect ( bodyRow2Columns [ 2 ] ) . toHaveTextContent ( "A0002" ) ;
119
+ expect ( bodyRow2Columns [ 3 ] ) . toHaveTextContent ( "파타고니아클래식 레트로-X 후리스 플리스 자켓" ) ;
120
+ expect ( bodyRow2Columns [ 4 ] ) . toHaveTextContent ( "230,000원" ) ;
121
+ expect ( bodyRow2Columns [ 5 ] ) . toHaveTextContent ( "SALE" ) ;
122
+ expect ( bodyRow2Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0211:00" ) ;
123
+ expect ( bodyRow2Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0211:00" ) ;
124
+
125
+ const bodyRow3Columns = tableBodyRows [ 3 ] . querySelectorAll ( "td" ) ;
126
+ expect ( bodyRow3Columns ) . toHaveLength ( 8 ) ;
127
+ expect ( bodyRow3Columns [ 2 ] ) . toHaveTextContent ( "A0003" ) ;
128
+ expect ( bodyRow3Columns [ 3 ] ) . toHaveTextContent ( "다이슨dyson v15 detect complete" ) ;
129
+ expect ( bodyRow3Columns [ 4 ] ) . toHaveTextContent ( "1,290,000원" ) ;
130
+ expect ( bodyRow3Columns [ 5 ] ) . toHaveTextContent ( "SOLDOUT" ) ;
131
+ expect ( bodyRow3Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0212:00" ) ;
132
+ expect ( bodyRow3Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0212:00" ) ;
133
+
134
+ const bodyRow4Columns = tableBodyRows [ 4 ] . querySelectorAll ( "td" ) ;
135
+ expect ( bodyRow4Columns ) . toHaveLength ( 8 ) ;
136
+ expect ( bodyRow4Columns [ 2 ] ) . toHaveTextContent ( "A0004" ) ;
137
+ expect ( bodyRow4Columns [ 3 ] ) . toHaveTextContent ( "Aēsop레저렉션 아로마틱 핸드 워시" ) ;
138
+ expect ( bodyRow4Columns [ 4 ] ) . toHaveTextContent ( "47,000원" ) ;
139
+ expect ( bodyRow4Columns [ 5 ] ) . toHaveTextContent ( "NOTSALE" ) ;
140
+ expect ( bodyRow4Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0201:00" ) ;
141
+ expect ( bodyRow4Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0201:00" ) ;
142
+
143
+ const bodyRow5Columns = tableBodyRows [ 5 ] . querySelectorAll ( "td" ) ;
144
+ expect ( bodyRow5Columns ) . toHaveLength ( 8 ) ;
145
+ expect ( bodyRow5Columns [ 2 ] ) . toHaveTextContent ( "A0005" ) ;
146
+ expect ( bodyRow5Columns [ 3 ] ) . toHaveTextContent ( "LUSH더티 보디 스프레이" ) ;
147
+ expect ( bodyRow5Columns [ 4 ] ) . toHaveTextContent ( "60,000원" ) ;
148
+ expect ( bodyRow5Columns [ 5 ] ) . toHaveTextContent ( "SALE" ) ;
149
+ expect ( bodyRow5Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0202:00" ) ;
150
+ expect ( bodyRow5Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0202:00" ) ;
151
+ } ) ;
152
+
153
+ it ( "URL 파라메터 page=2 이면 2페이지에 해당하는 아이템을 최대 5개를 테이블에 보여준다" , async ( ) => {
154
+ // given
155
+ when ( useProducts as jest . Mock ) . calledWith ( {
156
+ page : 2
157
+ } ) . mockReturnValue ( {
158
+ data : {
159
+ data : {
160
+ page : {
161
+ currentPage : 1 ,
162
+ pageSize : 5 ,
163
+ totalPage : 1 ,
164
+ totalCount : 6
165
+ } ,
166
+ items : [
167
+ {
168
+ id : 6 ,
169
+ code : "A0006" ,
170
+ brand : "블루보틀" ,
171
+ name : "쓰리 아프리카스" ,
172
+ price : 25000 ,
173
+ status : "SALE" ,
174
+ createdAt : dayjs ( "2023-02-02T15:00:00+09:00" ) ,
175
+ updatedAt : dayjs ( "2023-02-02T15:00:00+09:00" ) ,
176
+ } ,
177
+ ]
178
+ }
179
+ }
180
+ } ) ;
181
+
182
+ // when
183
+ await mockRouter . push ( "/sample/product/list?page=2" ) ;
184
+ render ( < ProductListPage /> )
185
+ await waitFor ( ( ) => screen . getByTestId ( "product-table" ) ) ;
186
+
187
+ // then
188
+ const productTable = screen . getByTestId ( "product-table" ) ;
189
+ expect ( productTable ) . toBeInTheDocument ( ) ;
190
+
191
+ // 테이블 바디 확인
192
+ const tableBodyRows = productTable . querySelectorAll ( "tbody > tr" ) ;
193
+ expect ( tableBodyRows ) . toHaveLength ( 2 ) ; // ant table은 컨텐츠이 담기지 않는 TR이 하나 존재하기 때문에 컨텐츠 + 1를 확인한다.
194
+
195
+ const bodyRow1Columns = tableBodyRows [ 1 ] . querySelectorAll ( "td" ) ;
196
+ expect ( bodyRow1Columns ) . toHaveLength ( 8 ) ;
197
+ expect ( bodyRow1Columns [ 2 ] ) . toHaveTextContent ( "A0006" ) ;
198
+ expect ( bodyRow1Columns [ 3 ] ) . toHaveTextContent ( "블루보틀쓰리 아프리카스" ) ;
199
+ expect ( bodyRow1Columns [ 4 ] ) . toHaveTextContent ( "25,000원" ) ;
200
+ expect ( bodyRow1Columns [ 5 ] ) . toHaveTextContent ( "SALE" ) ;
201
+ expect ( bodyRow1Columns [ 6 ] ) . toHaveTextContent ( "2023/02/0203:00" ) ;
202
+ expect ( bodyRow1Columns [ 7 ] ) . toHaveTextContent ( "2023/02/0203:00" ) ;
203
+ } ) ;
204
+ } ) ;
205
+
206
+ describe ( "버튼 이벤트" , ( ) => {
207
+ it ( "상품 등록 버튼을 클릭하면 상품 등록 페이지로 이동한다" , async ( ) => {
208
+ // given
209
+ when ( useProducts as jest . Mock ) . calledWith ( {
210
+ page : 1
211
+ } ) . mockReturnValue ( { } ) ;
212
+
213
+ await mockRouter . push ( "/sample/product/list" ) ;
214
+ render ( < ProductListPage /> )
215
+ await waitFor ( ( ) => screen . getByTestId ( "create-product-btn" ) ) ;
216
+
217
+ // when
218
+ const button = screen . getByTestId ( "create-product-btn" ) ;
219
+ fireEvent . click ( button ) ;
220
+
221
+ // then
222
+ expect ( mockRouter ) . toMatchObject ( {
223
+ pathname : "/sample/product/new" ,
224
+ query : { } ,
225
+ } ) ;
226
+ } ) ;
227
+ } ) ;
0 commit comments