1
- import { screen } from '@testing-library/react' ;
1
+ import React from 'react' ;
2
+ import { useSearchParams } from 'react-router-dom' ;
3
+ import { Table as PfTable , TableHeader } from '@patternfly/react-table/deprecated' ;
4
+ import { screen , fireEvent , waitFor } from '@testing-library/react' ;
2
5
import { ApplicationKind } from '../../../types' ;
3
6
import {
4
7
createK8sWatchResourceMock ,
5
8
createUseWorkspaceInfoMock ,
6
9
renderWithQueryClient ,
7
10
} from '../../../utils/test-utils' ;
11
+ import ApplicationListRow from '../ApplicationListRow' ;
8
12
import ApplicationListView from '../ApplicationListView' ;
9
13
10
14
jest . mock ( 'react-i18next' , ( ) => ( {
@@ -16,6 +20,7 @@ jest.mock('react-router-dom', () => {
16
20
return {
17
21
...actual ,
18
22
useLocation : jest . fn ( ( ) => ( { } ) ) ,
23
+ useSearchParams : jest . fn ( ) ,
19
24
Link : ( props ) => < a href = { props . to } > { props . children } </ a > ,
20
25
useNavigate : jest . fn ( ) ,
21
26
} ;
@@ -25,6 +30,30 @@ jest.mock('../../../utils/rbac', () => ({
25
30
useAccessReviewForModel : jest . fn ( ( ) => [ true , true ] ) ,
26
31
} ) ) ;
27
32
33
+ jest . mock ( '../../../shared/components/table' , ( ) => {
34
+ const actual = jest . requireActual ( '../../../shared/components/table' ) ;
35
+ return {
36
+ ...actual ,
37
+ Table : ( props ) => {
38
+ const { data, filters, selected, match, kindObj } = props ;
39
+ const cProps = { data, filters, selected, match, kindObj } ;
40
+ const columns = props . Header ( cProps ) ;
41
+ return (
42
+ < PfTable role = "table" aria-label = "table" cells = { columns } variant = "compact" borders = { false } >
43
+ < TableHeader role = "rowgroup" />
44
+ < tbody >
45
+ { props . data . map ( ( d , i ) => (
46
+ < tr key = { i } >
47
+ < ApplicationListRow columns = { null } obj = { d } />
48
+ </ tr >
49
+ ) ) }
50
+ </ tbody >
51
+ </ PfTable >
52
+ ) ;
53
+ } ,
54
+ } ;
55
+ } ) ;
56
+
28
57
const applications : ApplicationKind [ ] = [
29
58
{
30
59
kind : 'Application' ,
@@ -88,12 +117,17 @@ const applications: ApplicationKind[] = [
88
117
} ,
89
118
] ;
90
119
120
+ const useSearchParamsMock = useSearchParams as jest . Mock ;
91
121
const watchResourceMock = createK8sWatchResourceMock ( ) ;
92
122
createUseWorkspaceInfoMock ( { namespace : 'test-ns' , workspace : 'test-ws' } ) ;
93
123
94
124
const ApplicationList = ApplicationListView ;
95
125
96
126
describe ( 'Application List' , ( ) => {
127
+ beforeEach ( ( ) => {
128
+ useSearchParamsMock . mockImplementation ( ( ) => React . useState ( new URLSearchParams ( ) ) ) ;
129
+ } ) ;
130
+
97
131
it ( 'should render spinner if application data is not loaded' , ( ) => {
98
132
watchResourceMock . mockReturnValue ( [ [ ] , false ] ) ;
99
133
renderWithQueryClient ( < ApplicationList /> ) ;
@@ -130,4 +164,116 @@ describe('Application List', () => {
130
164
renderWithQueryClient ( < ApplicationList /> ) ;
131
165
expect ( screen . queryByTestId ( 'applications-breadcrumb-link' ) ) . not . toBeInTheDocument ( ) ;
132
166
} ) ;
167
+
168
+ it ( 'should apply query params to the filter' , async ( ) => {
169
+ watchResourceMock . mockReturnValue ( [ applications , true ] ) ;
170
+ useSearchParamsMock . mockImplementation ( ( ) =>
171
+ React . useState ( new URLSearchParams ( 'name=xyz-app' ) ) ,
172
+ ) ;
173
+ renderWithQueryClient ( < ApplicationList /> ) ;
174
+ await waitFor ( ( ) => {
175
+ expect ( screen . queryByText ( 'mno-app' ) ) . not . toBeInTheDocument ( ) ;
176
+ expect ( screen . queryByText ( 'mno-app1' ) ) . not . toBeInTheDocument ( ) ;
177
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
178
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
179
+ } ) ;
180
+ } ) ;
181
+
182
+ it ( 'should filter applications by name' , async ( ) => {
183
+ watchResourceMock . mockReturnValue ( [ applications , true ] ) ;
184
+ const { rerender } = renderWithQueryClient ( < ApplicationList /> ) ;
185
+ await waitFor ( ( ) => {
186
+ expect ( screen . queryByText ( 'mno-app' ) ) . toBeInTheDocument ( ) ;
187
+ expect ( screen . queryByText ( 'mno-app1' ) ) . toBeInTheDocument ( ) ;
188
+ expect ( screen . queryByText ( 'mno-app2' ) ) . toBeInTheDocument ( ) ;
189
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
190
+ } ) ;
191
+
192
+ const filter = screen . getByPlaceholderText ( 'Filter by name...' ) ;
193
+ fireEvent . change ( filter , { target : { value : 'xyz-app' } } ) ;
194
+ rerender ( < ApplicationList /> ) ;
195
+ await waitFor ( ( ) => {
196
+ expect ( screen . queryByText ( 'mno-app' ) ) . not . toBeInTheDocument ( ) ;
197
+ expect ( screen . queryByText ( 'mno-app1' ) ) . not . toBeInTheDocument ( ) ;
198
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
199
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
200
+ } ) ;
201
+ } ) ;
202
+
203
+ it ( 'should use fallback filter value of metadata.name' , async ( ) => {
204
+ const alteredApplications = applications . map ( ( app ) => ( {
205
+ ...app ,
206
+ spec : { displayName : undefined } ,
207
+ } ) ) ;
208
+ watchResourceMock . mockReturnValue ( [ alteredApplications , true ] ) ;
209
+ const { rerender } = renderWithQueryClient ( < ApplicationList /> ) ;
210
+ await waitFor ( ( ) => {
211
+ expect ( screen . queryByText ( 'mno-app' ) ) . toBeInTheDocument ( ) ;
212
+ expect ( screen . queryByText ( 'mno-app1' ) ) . toBeInTheDocument ( ) ;
213
+ expect ( screen . queryByText ( 'mno-app2' ) ) . toBeInTheDocument ( ) ;
214
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
215
+ } ) ;
216
+
217
+ const filter = screen . getByPlaceholderText ( 'Filter by name...' ) ;
218
+ fireEvent . change ( filter , { target : { value : 'xyz-app' } } ) ;
219
+ rerender ( < ApplicationList /> ) ;
220
+ await waitFor ( ( ) => {
221
+ expect ( screen . queryByText ( 'mno-app' ) ) . not . toBeInTheDocument ( ) ;
222
+ expect ( screen . queryByText ( 'mno-app1' ) ) . not . toBeInTheDocument ( ) ;
223
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
224
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
225
+ } ) ;
226
+ } ) ;
227
+
228
+ it ( 'should filter case insensitive' , async ( ) => {
229
+ watchResourceMock . mockReturnValue ( [ applications , true ] ) ;
230
+ const { rerender } = renderWithQueryClient ( < ApplicationList /> ) ;
231
+ await waitFor ( ( ) => {
232
+ expect ( screen . queryByText ( 'mno-app' ) ) . toBeInTheDocument ( ) ;
233
+ expect ( screen . queryByText ( 'mno-app1' ) ) . toBeInTheDocument ( ) ;
234
+ expect ( screen . queryByText ( 'mno-app2' ) ) . toBeInTheDocument ( ) ;
235
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
236
+ } ) ;
237
+
238
+ const filter = screen . getByPlaceholderText ( 'Filter by name...' ) ;
239
+ fireEvent . change ( filter , { target : { value : 'XYZ' } } ) ;
240
+ rerender ( < ApplicationList /> ) ;
241
+ await waitFor ( ( ) => {
242
+ expect ( screen . queryByText ( 'mno-app' ) ) . not . toBeInTheDocument ( ) ;
243
+ expect ( screen . queryByText ( 'mno-app1' ) ) . not . toBeInTheDocument ( ) ;
244
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
245
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
246
+ } ) ;
247
+ } ) ;
248
+
249
+ it ( 'should clear the filter when clear button is clicked' , async ( ) => {
250
+ watchResourceMock . mockReturnValue ( [ applications , true ] ) ;
251
+ const { rerender } = renderWithQueryClient ( < ApplicationList /> ) ;
252
+ await waitFor ( ( ) => {
253
+ expect ( screen . queryByText ( 'mno-app' ) ) . toBeInTheDocument ( ) ;
254
+ expect ( screen . queryByText ( 'mno-app1' ) ) . toBeInTheDocument ( ) ;
255
+ expect ( screen . queryByText ( 'mno-app2' ) ) . toBeInTheDocument ( ) ;
256
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
257
+ } ) ;
258
+
259
+ const filter = screen . getByPlaceholderText ( 'Filter by name...' ) ;
260
+ fireEvent . change ( filter , { target : { value : 'invalid-app' } } ) ;
261
+ rerender ( < ApplicationList /> ) ;
262
+ await waitFor ( ( ) => {
263
+ expect ( screen . queryByText ( 'mno-app' ) ) . not . toBeInTheDocument ( ) ;
264
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
265
+ expect ( screen . queryByText ( 'mno-app2' ) ) . not . toBeInTheDocument ( ) ;
266
+ expect ( screen . queryByText ( 'xyz-app' ) ) . not . toBeInTheDocument ( ) ;
267
+ expect ( screen . queryByText ( 'No results found' ) ) . toBeInTheDocument ( ) ;
268
+ } ) ;
269
+
270
+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Clear all filters' } ) ) ;
271
+ rerender ( < ApplicationList /> ) ;
272
+ await waitFor ( ( ) => {
273
+ expect ( screen . queryByText ( 'mno-app' ) ) . toBeInTheDocument ( ) ;
274
+ expect ( screen . queryByText ( 'mno-app1' ) ) . toBeInTheDocument ( ) ;
275
+ expect ( screen . queryByText ( 'mno-app2' ) ) . toBeInTheDocument ( ) ;
276
+ expect ( screen . queryByText ( 'xyz-app' ) ) . toBeInTheDocument ( ) ;
277
+ } ) ;
278
+ } ) ;
133
279
} ) ;
0 commit comments