@@ -152,6 +152,7 @@ const COLUMN_SORT_ICON_TEST_ID = "SouthRoundedIcon";
152152 * @param tab - the tab to check
153153 * @returns - true if the test passes and false if the test fails
154154 */
155+ // eslint-disable-next-line sonarjs/cognitive-complexity -- Complex code just for diagnostic will be removed later
155156export async function testSortAzul (
156157 page : Page ,
157158 tab : TabDescription
@@ -200,7 +201,8 @@ export async function testSortAzul(
200201 await expect ( sortIconLocator ) . toHaveCSS ( "opacity" , "0" ) ;
201202 }
202203 // Click to sort
203- await columnSortLocator . click ( ) ;
204+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
205+ await columnSortLocator . dispatchEvent ( "click" ) ;
204206 // Expect the first element of the table to still be visible (may not have text)
205207 await expect (
206208 getFirstRowNthColumnCellLocator ( page , columnPosition )
@@ -218,6 +220,8 @@ export async function testSortAzul(
218220 return true ;
219221}
220222
223+ const SEARCH_BUTTON_NAME = "Search" ;
224+
221225/**
222226 * Checks that sorting the tab does not cause the first row of the table to break.
223227 * This test does not check whether the sort order is correct.
@@ -270,11 +274,15 @@ export async function testSortCatalog(
270274 await columnSortLocator . click ( ) ;
271275 // Expect the first cell to still be visible
272276 await expect ( firstElementTextLocator ) . toBeVisible ( ) ;
277+ const nonOverlappingElement = page . getByRole ( "button" , {
278+ name : SEARCH_BUTTON_NAME ,
279+ } ) ;
273280 const firstElementText = await hoverAndGetText (
274281 page ,
275282 columnObject ,
276283 0 ,
277- columnPosition
284+ columnPosition ,
285+ nonOverlappingElement
278286 ) ;
279287 // Click again
280288 await columnSortLocator . click ( ) ;
@@ -300,7 +308,11 @@ export async function testSelectableColumns(
300308 // Navigate to the tab
301309 await page . goto ( tab . url ) ;
302310 // Select the "Edit Columns" menu
303- await page . getByRole ( "button" ) . getByText ( "Edit Columns" ) . click ( ) ;
311+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
312+ await page
313+ . getByRole ( "button" )
314+ . getByText ( "Edit Columns" )
315+ . dispatchEvent ( "click" ) ;
304316 await expect ( page . getByRole ( "menu" ) ) . toBeVisible ( ) ;
305317 // Enable each selectable tab
306318 const tabObjectArray = Array . from ( Object . values ( tab . selectableColumns ) ) ;
@@ -385,7 +397,8 @@ export async function testFilterPresence(
385397 for ( const filterName of filterNames ) {
386398 // Check that each filter is visible and clickable
387399 await expect ( page . getByText ( filterRegex ( filterName ) ) ) . toBeVisible ( ) ;
388- await page . getByText ( filterRegex ( filterName ) ) . click ( ) ;
400+ // dispatchEvent necessary because the filter menu component sometimes interrupts a click event
401+ await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
389402 await expect ( page . getByRole ( "checkbox" ) . first ( ) ) . toBeVisible ( ) ;
390403 await expect ( page . getByRole ( "checkbox" ) . first ( ) ) . not . toBeChecked ( ) ;
391404 // Check that clicking out of the filter menu causes it to disappear
@@ -525,6 +538,7 @@ export async function testFilterPersistence(
525538 await page . locator ( "body" ) . click ( ) ;
526539 }
527540 // Return to the start tab and confirm that the filter stays checked and that some content is visible
541+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
528542 await page
529543 . getByRole ( "tab" )
530544 . getByText ( tabOrder [ 0 ] . tabName , { exact : true } )
@@ -557,6 +571,7 @@ export async function testFilterCounts(
557571 // For each arbitrarily selected filter
558572 for ( const filterName of filterNames ) {
559573 // Select the filter
574+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
560575 await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
561576 // Get the number associated with the first filter button, and select it
562577 await page . waitForLoadState ( "load" ) ;
@@ -574,6 +589,7 @@ export async function testFilterCounts(
574589 return false ;
575590 }
576591 // Check the filter
592+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
577593 await firstFilterOption . getByRole ( "checkbox" ) . dispatchEvent ( "click" ) ;
578594 await page . waitForLoadState ( "load" ) ;
579595 // Exit the filter menu
@@ -620,6 +636,7 @@ export async function testFilterTags(
620636 await page . goto ( tab . url ) ;
621637 for ( const filterName of filterNames ) {
622638 // Select a filter
639+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
623640 await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
624641 await page . waitForLoadState ( "load" ) ;
625642 const firstFilterOptionLocator = getFirstFilterOptionLocator ( page ) ;
@@ -664,6 +681,7 @@ export async function testClearAll(
664681 await page . goto ( tab . url ) ;
665682 const selectedFilterNamesList = [ ] ;
666683 // Select each filter and get the names of the actual filter text
684+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
667685 for ( const filterName of filterNames ) {
668686 await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
669687 await getFirstFilterOptionLocator ( page ) . getByRole ( "checkbox" ) . click ( ) ;
@@ -718,6 +736,7 @@ export async function testSelectFiltersThroughSearchBar(
718736 for ( const filterName of filterNames ) {
719737 // Get the first filter option
720738 await expect ( page . getByText ( filterRegex ( filterName ) ) ) . toBeVisible ( ) ;
739+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
721740 await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
722741 const firstFilterOptionLocator = getFirstFilterOptionLocator ( page ) ;
723742 const filterOptionName = await getFilterOptionName (
@@ -757,6 +776,7 @@ export async function testDeselectFiltersThroughSearchBar(
757776 for ( const filterName of filterNames ) {
758777 // Select each filter option
759778 await expect ( page . getByText ( filterRegex ( filterName ) ) ) . toBeVisible ( ) ;
779+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
760780 await page . getByText ( filterRegex ( filterName ) ) . dispatchEvent ( "click" ) ;
761781 const firstFilterOptionLocator = getFirstFilterOptionLocator ( page ) ;
762782 const filterOptionName = await getFilterOptionName (
@@ -869,6 +889,7 @@ export async function testExportBackpage(
869889 ) ;
870890 await expect ( grantedRowLocator ) . toBeVisible ( ) ;
871891 // Click into the selected row
892+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
872893 await grantedRowLocator . dispatchEvent ( "click" ) ;
873894 await expect (
874895 page . getByText ( tab . backpageExportButtons . detailsName )
@@ -935,6 +956,7 @@ export async function testBackpageAccess(
935956 tab . backpageAccessTags . grantedShortName
936957 ) ;
937958 await expect ( grantedRowLocator ) . toBeVisible ( ) ;
959+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
938960 await grantedRowLocator . dispatchEvent ( "click" ) ;
939961 await expect (
940962 page . getByText ( tab . backpageExportButtons . detailsName )
@@ -961,6 +983,7 @@ export async function testBackpageAccess(
961983 tab . backpageAccessTags . deniedShortName
962984 ) ;
963985 await expect ( deniedRowLocator ) . toBeVisible ( ) ;
986+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
964987 await deniedRowLocator . dispatchEvent ( "click" ) ;
965988 await expect (
966989 page . getByText ( tab . backpageAccessTags . deniedLongName )
@@ -986,13 +1009,15 @@ export async function testBackpageAccess(
9861009 * @param columnDescription - a columnDescription object for the column
9871010 * @param rowPosition - the zero-indexed position of the row
9881011 * @param columnPosition - the zero-indexed position of the column
1012+ * @param nonOverlappingElement - a locator for an element that does not overlap with a possble tooltip
9891013 * @returns - a Promise with the cell's text
9901014 */
9911015const hoverAndGetText = async (
9921016 page : Page ,
9931017 columnDescription : ColumnDescription | undefined ,
9941018 rowPosition : number ,
995- columnPosition : number
1019+ columnPosition : number ,
1020+ nonOverlappingElement : Locator
9961021) : Promise < string > => {
9971022 const cellLocator = getMthRowNthColumnCellLocator (
9981023 page ,
@@ -1014,14 +1039,16 @@ const hoverAndGetText = async (
10141039 await page . getByRole ( "tooltip" ) . waitFor ( ) ;
10151040 const outputText = ( await page . getByRole ( "tooltip" ) . innerText ( ) ) . trim ( ) ;
10161041 // Hover over a different part of the page to ensure that the tooltip disappears
1017- await page . getByRole ( "columnheader" ) . first ( ) . hover ( ) ;
1042+ await nonOverlappingElement . hover ( ) ;
10181043 await expect ( page . getByRole ( "tooltip" ) ) . toHaveCount ( 0 ) ;
10191044 // Return the tooltip contents
10201045 return outputText ;
10211046 }
10221047 return cellText . trim ( ) ;
10231048} ;
10241049
1050+ const FOOTER_LINK_NAME = "Privacy" ;
1051+
10251052/**
10261053 * Check that the details in the backpage sidebar match information in the data table
10271054 * @param page - a Playwright page object
@@ -1073,7 +1100,16 @@ export async function testBackpageDetails(
10731100 ( x ) => x . name == columnHeaderName
10741101 ) ;
10751102 // Get the entry text
1076- const tableEntryText = await hoverAndGetText ( page , columnObject , 0 , i ) ;
1103+ const nonOverlappingElement = page . getByRole ( "link" , {
1104+ name : FOOTER_LINK_NAME ,
1105+ } ) ;
1106+ const tableEntryText = await hoverAndGetText (
1107+ page ,
1108+ columnObject ,
1109+ 0 ,
1110+ i ,
1111+ nonOverlappingElement
1112+ ) ;
10771113 // Get the name of the corresponding header on the backpage
10781114 const correspondingHeaderName = tab . backpageHeaders . find (
10791115 ( header : BackpageHeader ) =>
@@ -1323,6 +1359,7 @@ export async function filterAndTestLastPagePagination(
13231359 ) ;
13241360 // Paginate forwards
13251361 for ( let i = 2 ; i < maxPages + 1 ; i ++ ) {
1362+ // (dispatchevent necessary because the filter menu sometimes interrupts the click event)
13261363 await page
13271364 . getByRole ( "button" )
13281365 . filter ( { has : page . getByTestId ( FORWARD_BUTTON_TEST_ID ) } )
@@ -1381,10 +1418,11 @@ export async function testPaginationContent(
13811418 await expect ( firstElementTextLocator ) . not . toHaveText ( "" ) ;
13821419 const OriginalFirstTableEntry = await firstElementTextLocator . innerText ( ) ;
13831420 // Click the next button
1421+ // dispatchEvent necessary because the table loading component sometimes interrupts a click event
13841422 await page
13851423 . getByRole ( "button" )
13861424 . filter ( { has : page . getByTestId ( FORWARD_BUTTON_TEST_ID ) } )
1387- . click ( ) ;
1425+ . dispatchEvent ( "click" ) ;
13881426 // Expect the page count to have incremented
13891427 await expect ( page . getByText ( PAGE_COUNT_REGEX , { exact : true } ) ) . toHaveText (
13901428 RegExp ( `Page ${ i } of [0-9]+` )
0 commit comments