@@ -45,14 +45,20 @@ export class DataExplorer {
45
45
selectColumnButton : Locator ;
46
46
selectConditionButton : Locator ;
47
47
applyFilterButton : Locator ;
48
+ selectFilterModalValue : ( value : string ) => Locator ;
49
+ filteringMenu : Locator ;
50
+ menuItemClearFilters : Locator ;
48
51
49
52
constructor ( private code : Code , private workbench : Workbench ) {
50
53
this . clearSortingButton = this . code . driver . page . locator ( CLEAR_SORTING_BUTTON ) ;
51
54
this . clearFilterButton = this . code . driver . page . locator ( CLEAR_FILTER_BUTTON ) ;
52
55
this . addFilterButton = this . code . driver . page . getByRole ( 'button' , { name : 'Add Filter' } ) ;
53
56
this . selectColumnButton = this . code . driver . page . getByRole ( 'button' , { name : 'Select Column' } ) ;
54
57
this . selectConditionButton = this . code . driver . page . getByRole ( 'button' , { name : 'Select Condition' } ) ;
58
+ this . selectFilterModalValue = ( value : string ) => this . code . driver . page . locator ( '.positron-modal-popup' ) . getByRole ( 'button' , { name : value } ) ;
55
59
this . applyFilterButton = this . code . driver . page . getByRole ( 'button' , { name : 'Apply Filter' } ) ;
60
+ this . filteringMenu = this . code . driver . page . getByRole ( 'button' , { name : 'Filtering' } ) ;
61
+ this . menuItemClearFilters = this . code . driver . page . getByRole ( 'button' , { name : 'Clear Filters' } ) ;
56
62
}
57
63
58
64
async clearAllFilters ( ) {
@@ -109,20 +115,23 @@ export class DataExplorer {
109
115
/*
110
116
* Add a filter to the data explorer. Only works for a single filter at the moment.
111
117
*/
112
- async addFilter ( columnName : string , functionText : string , filterValue : string ) {
113
- await test . step ( `Add filter: ${ columnName } ${ functionText } ${ filterValue } ` , async ( ) => {
118
+ async addFilter ( columnName : string , condition : string , value ? : string ) {
119
+ await test . step ( `Add filter: ${ columnName } ${ condition } ${ value } ` , async ( ) => {
114
120
await this . addFilterButton . click ( ) ;
115
121
116
122
// select column
117
123
await this . selectColumnButton . click ( ) ;
118
- await this . code . driver . page . getByRole ( 'button' , { name : columnName } ) . click ( ) ;
124
+ await this . selectFilterModalValue ( columnName ) . click ( ) ;
119
125
120
126
// select condition
121
127
await this . selectConditionButton . click ( ) ;
122
- await this . code . driver . page . getByRole ( 'button' , { name : functionText , exact : true } ) . click ( ) ;
128
+ await this . selectFilterModalValue ( condition ) . click ( ) ;
123
129
124
130
// enter value
125
- await this . code . driver . page . getByRole ( 'textbox' , { name : 'value' } ) . fill ( filterValue ) ;
131
+ if ( value ) {
132
+ await this . code . driver . page . getByRole ( 'textbox' , { name : 'value' } ) . fill ( value ) ;
133
+ }
134
+
126
135
await this . applyFilterButton . click ( ) ;
127
136
} ) ;
128
137
}
@@ -285,23 +294,40 @@ export class DataExplorer {
285
294
} ) ;
286
295
}
287
296
288
- async verifyTableData ( expectedData : Array < { [ key : string ] : string } > , timeout = 60000 ) {
297
+ async verifyTableData ( expectedData : Array < { [ key : string ] : string | number } > , timeout = 60000 ) {
289
298
await test . step ( 'Verify data explorer data' , async ( ) => {
290
299
await expect ( async ( ) => {
291
300
const tableData = await this . getDataExplorerTableData ( ) ;
292
-
293
301
expect ( tableData . length ) . toBe ( expectedData . length ) ;
294
302
295
303
for ( let i = 0 ; i < expectedData . length ; i ++ ) {
296
304
const row = expectedData [ i ] ;
297
- for ( const [ key , value ] of Object . entries ( row ) ) {
298
- expect ( tableData [ i ] [ key ] ) . toBe ( value ) ;
305
+ for ( const [ key , expectedValue ] of Object . entries ( row ) ) {
306
+ const actualValue = tableData [ i ] [ key ] ;
307
+ expect ( this . normalize ( actualValue ) ) . toBe ( this . normalize ( expectedValue ) ) ;
299
308
}
300
309
}
301
310
} ) . toPass ( { timeout } ) ;
302
311
} ) ;
303
312
}
304
313
314
+ private normalize ( value : unknown ) : string {
315
+ const str = String ( value ) . trim ( ) . toUpperCase ( ) ;
316
+
317
+ // Handle true missing values only
318
+ if ( value === null || value === undefined || [ 'NA' , 'NAN' , 'NULL' ] . includes ( str ) ) {
319
+ return '__MISSING__' ;
320
+ }
321
+
322
+ // If value is numeric (e.g., '25.0'), normalize precision
323
+ const num = Number ( value ) ;
324
+ if ( ! isNaN ( num ) ) {
325
+ return String ( num ) ;
326
+ }
327
+
328
+ return String ( value ) . trim ( ) ;
329
+ }
330
+
305
331
async verifyTableDataLength ( expectedLength : number ) {
306
332
await test . step ( 'Verify data explorer table data length' , async ( ) => {
307
333
await expect ( async ( ) => {
@@ -394,4 +420,8 @@ export class DataExplorer {
394
420
await cellLocator . click ( ) ;
395
421
} ) ;
396
422
}
423
+
424
+ async clickCopyAsCodeButton ( ) {
425
+ await this . workbench . editorActionBar . clickButton ( 'Copy as Code' ) ;
426
+ }
397
427
}
0 commit comments