1
- import { fireEvent , render , screen , waitFor } from '@testing-library/react'
1
+ import { fireEvent , render , screen , waitFor , within } from '@testing-library/react'
2
2
import React from 'react'
3
3
import { beforeEach , describe , expect , it , vi } from 'vitest'
4
- import type { AppId } from '@/config/apps'
5
- import { DeepScanModal , type DeepScanOptions } from '../deep-scan-modal'
4
+ import { DeepScanModal } from '../deep-scan-modal'
6
5
7
6
// Mock UI components
8
7
vi . mock ( '@/components/ui/dialog' , ( ) => ( {
@@ -27,15 +26,15 @@ vi.mock('@/components/ui/input', () => ({
27
26
} ) )
28
27
29
28
vi . mock ( '@/components/ui/tabs' , ( ) => ( {
30
- Tabs : ( { children, value, onValueChange } : any ) => {
29
+ Tabs : ( { children, value, onValueChange, 'data-testid' : dataTestId } : any ) => {
31
30
const childrenWithProps = React . Children . map ( children , child => {
32
31
if ( React . isValidElement ( child ) ) {
33
32
return React . cloneElement ( child as any , { currentValue : value , onValueChange } )
34
33
}
35
34
return child
36
35
} )
37
36
return (
38
- < div data-testid = " tabs" data-value = { value } >
37
+ < div data-testid = { dataTestId || ' tabs' } data-value = { value } >
39
38
{ childrenWithProps }
40
39
</ div >
41
40
)
@@ -56,22 +55,26 @@ vi.mock('@/components/ui/tabs', () => ({
56
55
} )
57
56
return < div data-testid = "tabs-list" > { childrenWithProps } </ div >
58
57
} ,
59
- TabsTrigger : ( { children, value, onValueChange } : any ) => (
60
- < button data-testid = { `tab-trigger-${ value } ` } onClick = { ( ) => onValueChange ?.( value ) } >
58
+ TabsTrigger : ( { children, value, onValueChange, 'data-testid' : dataTestId } : any ) => (
59
+ < button type = "button" data-testid = { dataTestId || `tab-trigger-${ value } ` } onClick = { ( ) => onValueChange ?.( value ) } >
61
60
{ children }
62
61
</ button >
63
62
) ,
64
63
} ) )
65
64
66
65
vi . mock ( '@/components/ui/select' , ( ) => ( {
67
- Select : ( { children, value, onValueChange } : any ) => (
66
+ Select : ( { children, value } : any ) => (
68
67
< div data-testid = "select" data-value = { value } >
69
68
{ children }
70
69
</ div >
71
70
) ,
72
71
SelectContent : ( { children } : any ) => < div data-testid = "select-content" > { children } </ div > ,
73
72
SelectItem : ( { children, value } : any ) => < div data-testid = { `select-item-${ value } ` } > { children } </ div > ,
74
- SelectTrigger : ( { children } : any ) => < button data-testid = "select-trigger" > { children } </ button > ,
73
+ SelectTrigger : ( { children } : any ) => (
74
+ < button type = "button" data-testid = "select-trigger" >
75
+ { children }
76
+ </ button >
77
+ ) ,
75
78
SelectValue : ( { placeholder } : any ) => < span > { placeholder } </ span > ,
76
79
} ) )
77
80
@@ -162,57 +165,53 @@ describe('DeepScanModal', () => {
162
165
} )
163
166
164
167
it ( 'should generate correct path for account range + address range' , async ( ) => {
165
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
168
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
166
169
167
170
// Switch to account range tab
168
- const accountRangeTab = container . querySelector ( '[data-testid="tab-trigger-range"]' )
169
- if ( accountRangeTab ) {
170
- fireEvent . click ( accountRangeTab )
171
- }
171
+ const accountTabs = screen . getByTestId ( 'account-tabs' )
172
+ const accountRangeTab = within ( accountTabs ) . getByTestId ( 'account-range-tab' )
173
+ fireEvent . click ( accountRangeTab )
172
174
173
- // Switch to address range tab (need to find the second tabs component)
174
- const allRangeTabs = container . querySelectorAll ( '[data-testid="tab-trigger-range"]' )
175
- if ( allRangeTabs [ 1 ] ) {
176
- fireEvent . click ( allRangeTabs [ 1 ] )
177
- }
175
+ // Switch to address range tab
176
+ const addressTabs = screen . getByTestId ( 'address-tabs' )
177
+ const addressRangeTab = within ( addressTabs ) . getByTestId ( 'address-range-tab' )
178
+ fireEvent . click ( addressRangeTab )
178
179
179
180
// Wait for re-render
180
181
await waitFor ( ( ) => {
181
182
// Check for range notation in path
182
- const pathText = container . textContent || ''
183
- expect ( pathText ) . toMatch ( / m \/ 4 4 ' \/ 3 5 4 ' \/ \{ 1 \. \. \. 5 \} ' \/ 0 ' \/ \{ 0 \. \. \. 5 \} ' / i)
183
+ expect ( screen . getByText ( / m \/ 4 4 ' \/ 3 5 4 ' \/ \{ 1 \. \. \. 5 \} ' \/ 0 ' \/ \{ 0 \. \. \. 5 \} ' / i) ) . toBeInTheDocument ( )
184
184
} )
185
185
} )
186
186
187
187
it ( 'should handle same start and end indices in range' , async ( ) => {
188
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
188
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
189
189
190
190
// Switch to account range tab
191
- const accountRangeTab = container . querySelector ( '[data-testid="tab-trigger-range"]' )
192
- if ( accountRangeTab ) {
193
- fireEvent . click ( accountRangeTab )
194
- }
191
+ const accountTabs = screen . getByTestId ( 'account-tabs' )
192
+ const accountRangeTab = within ( accountTabs ) . getByTestId ( 'account-range-tab' )
193
+ fireEvent . click ( accountRangeTab )
195
194
196
- // Set same start and end for account range
197
- const inputs = container . querySelectorAll ( 'input[type="number"]' )
198
- const startInput = inputs [ 0 ] as HTMLInputElement
199
- const endInput = inputs [ 1 ] as HTMLInputElement
195
+ // Set same start and end for account range using label text
196
+ const startInputs = screen . getAllByLabelText ( 'Start Index' )
197
+ const endInputs = screen . getAllByLabelText ( 'End Index' )
198
+ const accountStartInput = startInputs [ 0 ] // Account section comes first
199
+ const accountEndInput = endInputs [ 0 ]
200
200
201
- fireEvent . change ( startInput , { target : { value : '3' } } )
202
- fireEvent . change ( endInput , { target : { value : '3' } } )
201
+ fireEvent . change ( accountStartInput , { target : { value : '3' } } )
202
+ fireEvent . change ( accountEndInput , { target : { value : '3' } } )
203
203
204
204
await waitFor ( ( ) => {
205
- const pathText = container . textContent || ''
206
205
// When start equals end, should show single value, not range
207
- expect ( pathText ) . toMatch ( / m \/ 4 4 ' \/ 3 5 4 ' \/ 3 ' \/ 0 ' / i)
206
+ expect ( screen . getByText ( / m \/ 4 4 ' \/ 3 5 4 ' \/ 3 ' \/ 0 ' / i) ) . toBeInTheDocument ( )
208
207
} )
209
208
} )
210
209
211
210
it ( 'should update path when chain selection changes' , ( ) => {
212
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
211
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
213
212
214
213
// Initial path should use Polkadot coin type (354)
215
- expect ( container . textContent ) . toMatch ( / m \/ 4 4 ' \/ 3 5 4 ' / i)
214
+ expect ( screen . getByText ( / m \/ 4 4 ' \/ 3 5 4 ' / i) ) . toBeInTheDocument ( )
216
215
217
216
// Note: Full chain selection testing would require more complex mocking
218
217
// of the Select component to properly simulate selection changes
@@ -241,21 +240,21 @@ describe('DeepScanModal', () => {
241
240
} )
242
241
243
242
it ( 'should disable scan button when range end is less than start' , async ( ) => {
244
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
243
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
245
244
246
245
// Switch to account range tab
247
- const accountRangeTab = container . querySelector ( '[data-testid="tab-trigger-range"]' )
248
- if ( accountRangeTab ) {
249
- fireEvent . click ( accountRangeTab )
250
- }
246
+ const accountTabs = screen . getByTestId ( 'account-tabs' )
247
+ const accountRangeTab = within ( accountTabs ) . getByTestId ( 'account-range-tab' )
248
+ fireEvent . click ( accountRangeTab )
251
249
252
250
await waitFor ( ( ) => {
253
- const inputs = container . querySelectorAll ( 'input[type="number"]' )
254
- const startInput = inputs [ 0 ] as HTMLInputElement
255
- const endInput = inputs [ 1 ] as HTMLInputElement
251
+ const startInputs = screen . getAllByLabelText ( 'Start Index' )
252
+ const endInputs = screen . getAllByLabelText ( 'End Index' )
253
+ const accountStartInput = startInputs [ 0 ] // Account section comes first
254
+ const accountEndInput = endInputs [ 0 ]
256
255
257
- fireEvent . change ( startInput , { target : { value : '5' } } )
258
- fireEvent . change ( endInput , { target : { value : '3' } } )
256
+ fireEvent . change ( accountStartInput , { target : { value : '5' } } )
257
+ fireEvent . change ( accountEndInput , { target : { value : '3' } } )
259
258
260
259
const scanButton = screen . getByText ( 'Start Deep Scan' )
261
260
expect ( scanButton ) . toBeDisabled ( )
@@ -299,23 +298,28 @@ describe('DeepScanModal', () => {
299
298
} )
300
299
301
300
it ( 'should generate correct options for account range + address range' , async ( ) => {
302
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
301
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
303
302
304
303
// Switch both to range mode
305
- const rangeTabs = container . querySelectorAll ( '[data-testid="tab-trigger-range"]' )
306
- if ( rangeTabs [ 0 ] ) fireEvent . click ( rangeTabs [ 0 ] ) // Account range
307
- if ( rangeTabs [ 1 ] ) fireEvent . click ( rangeTabs [ 1 ] ) // Address range
304
+ const accountTabs = screen . getByTestId ( 'account-tabs' )
305
+ const accountRangeTab = within ( accountTabs ) . getByTestId ( 'account-range-tab' )
306
+ fireEvent . click ( accountRangeTab )
307
+
308
+ const addressTabs = screen . getByTestId ( 'address-tabs' )
309
+ const addressRangeTab = within ( addressTabs ) . getByTestId ( 'address-range-tab' )
310
+ fireEvent . click ( addressRangeTab )
308
311
309
312
await waitFor ( ( ) => {
310
- const inputs = container . querySelectorAll ( 'input[type="number"]' )
313
+ const startInputs = screen . getAllByLabelText ( 'Start Index' )
314
+ const endInputs = screen . getAllByLabelText ( 'End Index' )
311
315
312
- // Set account range 2-5
313
- fireEvent . change ( inputs [ 0 ] , { target : { value : '2' } } )
314
- fireEvent . change ( inputs [ 1 ] , { target : { value : '5' } } )
316
+ // Set account range 2-5 (account inputs come first)
317
+ fireEvent . change ( startInputs [ 0 ] , { target : { value : '2' } } )
318
+ fireEvent . change ( endInputs [ 0 ] , { target : { value : '5' } } )
315
319
316
- // Set address range 1-10
317
- fireEvent . change ( inputs [ 2 ] , { target : { value : '1' } } )
318
- fireEvent . change ( inputs [ 3 ] , { target : { value : '10' } } )
320
+ // Set address range 1-10 (address inputs come second)
321
+ fireEvent . change ( startInputs [ 1 ] , { target : { value : '1' } } )
322
+ fireEvent . change ( endInputs [ 1 ] , { target : { value : '10' } } )
319
323
320
324
const scanButton = screen . getByText ( 'Start Deep Scan' )
321
325
fireEvent . click ( scanButton )
@@ -333,20 +337,22 @@ describe('DeepScanModal', () => {
333
337
} )
334
338
335
339
it ( 'should generate correct options for mixed modes' , async ( ) => {
336
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
340
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
337
341
338
342
// Keep account as single, switch address to range
339
- const rangeTabs = container . querySelectorAll ( '[data-testid="tab-trigger-range"]' )
340
- if ( rangeTabs [ 1 ] ) fireEvent . click ( rangeTabs [ 1 ] ) // Address range only
343
+ const addressTabs = screen . getByTestId ( 'address-tabs' )
344
+ const addressRangeTab = within ( addressTabs ) . getByTestId ( 'address-range-tab' )
345
+ fireEvent . click ( addressRangeTab )
341
346
342
347
await waitFor ( ( ) => {
343
348
const accountInput = screen . getByPlaceholderText ( '1' ) as HTMLInputElement
344
349
fireEvent . change ( accountInput , { target : { value : '3' } } )
345
350
346
- const inputs = container . querySelectorAll ( 'input[type="number"]' )
347
- // Set address range
348
- const addressStartInput = inputs [ 1 ] as HTMLInputElement
349
- const addressEndInput = inputs [ 2 ] as HTMLInputElement
351
+ const startInputs = screen . getAllByLabelText ( 'Start Index' )
352
+ const endInputs = screen . getAllByLabelText ( 'End Index' )
353
+ // Set address range (since account is single, address inputs will be the only ones)
354
+ const addressStartInput = startInputs [ 0 ] // Only address range inputs exist
355
+ const addressEndInput = endInputs [ 0 ]
350
356
fireEvent . change ( addressStartInput , { target : { value : '0' } } )
351
357
fireEvent . change ( addressEndInput , { target : { value : '5' } } )
352
358
@@ -386,22 +392,22 @@ describe('DeepScanModal', () => {
386
392
} )
387
393
388
394
it ( 'should show alert for large account ranges' , async ( ) => {
389
- const { container } = render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
395
+ render ( < DeepScanModal isOpen = { true } onClose = { mockOnClose } onScan = { mockOnScan } /> )
390
396
391
397
// Switch to account range
392
- const accountRangeTab = container . querySelector ( '[data-testid="tab-trigger-range"]' )
393
- if ( accountRangeTab ) {
394
- fireEvent . click ( accountRangeTab )
395
- }
398
+ const accountTabs = screen . getByTestId ( 'account-tabs' )
399
+ const accountRangeTab = within ( accountTabs ) . getByTestId ( 'account-range-tab' )
400
+ fireEvent . click ( accountRangeTab )
396
401
397
402
await waitFor ( ( ) => {
398
- const inputs = container . querySelectorAll ( 'input[type="number"]' )
399
- const startInput = inputs [ 0 ] as HTMLInputElement
400
- const endInput = inputs [ 1 ] as HTMLInputElement
403
+ const startInputs = screen . getAllByLabelText ( 'Start Index' )
404
+ const endInputs = screen . getAllByLabelText ( 'End Index' )
405
+ const accountStartInput = startInputs [ 0 ] // Account section comes first
406
+ const accountEndInput = endInputs [ 0 ]
401
407
402
408
// Set large range (more than 50)
403
- fireEvent . change ( startInput , { target : { value : '0' } } )
404
- fireEvent . change ( endInput , { target : { value : '60' } } )
409
+ fireEvent . change ( accountStartInput , { target : { value : '0' } } )
410
+ fireEvent . change ( accountEndInput , { target : { value : '60' } } )
405
411
406
412
const alert = screen . getByTestId ( 'alert' )
407
413
expect ( alert ) . toBeInTheDocument ( )
0 commit comments