From 030eb0510fcb9c7233de4708a78b3cc9d2174d74 Mon Sep 17 00:00:00 2001 From: mrrajan <86094767+mrrajan@users.noreply.github.com.> Date: Fri, 2 May 2025 21:44:41 +0530 Subject: [PATCH 1/5] To verify sorting of vulnerability table Signed-off-by: mrrajan <86094767+mrrajan@users.noreply.github.com.> --- .../@sbom-explorer/sbom-explorer.feature | 43 +++- .../@sbom-explorer/sbom-explorer.step.ts | 46 +++- .../vulnerability-explorer.step.ts | 4 +- tests/ui/helpers/SearchPage.ts | 8 +- tests/ui/helpers/ToolbarTable.ts | 230 ++++++++++++++++-- 5 files changed, 286 insertions(+), 45 deletions(-) diff --git a/tests/ui/features/@sbom-explorer/sbom-explorer.feature b/tests/ui/features/@sbom-explorer/sbom-explorer.feature index ba93907..95444a8 100644 --- a/tests/ui/features/@sbom-explorer/sbom-explorer.feature +++ b/tests/ui/features/@sbom-explorer/sbom-explorer.feature @@ -3,7 +3,7 @@ Feature: SBOM Explorer - View SBOM details Given User is authenticated Scenario Outline: View SBOM Overview - Given An ingested "" SBOM "" is available + Given An ingested SBOM "" is available When User visits SBOM details Page of "" Then The page title is "" And Tab "Info" is visible @@ -16,7 +16,7 @@ Feature: SBOM Explorer - View SBOM details | quarkus-bom | Scenario Outline: View SBOM Info (Metadata) - Given An ingested "" SBOM "" is available + Given An ingested SBOM "" is available When User visits SBOM details Page of "" Then Tab "Info" is selected Then "SBOM's name" is visible @@ -30,7 +30,7 @@ Feature: SBOM Explorer - View SBOM details | quarkus-bom | Scenario Outline: Downloading SBOM file - Given An ingested "" SBOM "" is available + Given An ingested SBOM "" is available When User visits SBOM details Page of "" Then "Download SBOM" action is invoked and downloaded filename is "" Then "Download License Report" action is invoked and downloaded filename is "" @@ -40,7 +40,7 @@ Feature: SBOM Explorer - View SBOM details | quarkus-bom | quarkus-bom.json | quarkus-bom_licenses.tar.gz | Scenario Outline: View list of SBOM Packages - Given An ingested "" SBOM "" is available + Given An ingested SBOM "" is available When User visits SBOM details Page of "" When User selects the Tab "Packages" # confirms its visible for all tabs @@ -63,7 +63,7 @@ Feature: SBOM Explorer - View SBOM details | SPDX | quarkus-bom | jdom | Scenario Outline: View SBOM Vulnerabilities - Given An ingested "" SBOM "" containing Vulnerabilities + Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" When User Clicks on Vulnerabilities Tab Action @@ -73,7 +73,7 @@ Feature: SBOM Explorer - View SBOM details Then SBOM Name "" should be visible inside the tab Then SBOM Version should be visible inside the tab Then SBOM Creation date should be visible inside the tab - # Then List of related Vulnerabilities should be sorted by "CVSS" in descending order + Then List of related Vulnerabilities should be sorted by "Id" in ascending order Examples: | sbomType | sbomName | @@ -81,7 +81,7 @@ Feature: SBOM Explorer - View SBOM details @slow Scenario Outline: Pagination of SBOM Vulnerabilities - Given An ingested "" SBOM "" containing Vulnerabilities + Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" Then Pagination of Vulnerabilities list works @@ -91,10 +91,37 @@ Feature: SBOM Explorer - View SBOM details @slow Scenario Outline: View paginated list of SBOM Packages - Given An ingested "" SBOM "" is available + Given An ingested SBOM "" is available When User visits SBOM details Page of "" When User selects the Tab "Packages" Then Pagination of Packages list works Examples: | sbomType | sbomName | | SPDX | quarkus-bom | + + Scenario Outline: Columns in list of SBOM Vulnerabilities + Given An ingested SBOM "" containing Vulnerabilities + When User visits SBOM details Page of "" + When User selects the Tab "Vulnerabilities" + Then List of Vulnerabilities has column "Id" + Then List of Vulnerabilities has column "Description" + Then List of Vulnerabilities has column "CVSS" + Then List of Vulnerabilities has column "Affected dependencies" + Then List of Vulnerabilities has column "Published" + Then List of Vulnerabilities has column "Updated" + Examples: + | sbomType | sbomName | + | SPDX | quarkus-bom | + + @slow + Scenario Outline: Sorting SBOM Vulnerabilities + Given An ingested SBOM "" containing Vulnerabilities + When User visits SBOM details Page of "" + When User selects the Tab "Vulnerabilities" + Then Table column "Description" is not sortable + Then Sorting of "Id, Affected dependencies, Published, Updated" Columns Works + #Then Sorting of "CVSS" Columns works + # Bug: https://issues.redhat.com/browse/TC-2598 + Examples: + | sbomType | sbomName | + | SPDX | quarkus-bom | \ No newline at end of file diff --git a/tests/ui/features/@sbom-explorer/sbom-explorer.step.ts b/tests/ui/features/@sbom-explorer/sbom-explorer.step.ts index 190f061..3697885 100644 --- a/tests/ui/features/@sbom-explorer/sbom-explorer.step.ts +++ b/tests/ui/features/@sbom-explorer/sbom-explorer.step.ts @@ -9,13 +9,10 @@ export const { Given, When, Then } = createBdd(); const PACKAGE_TABLE_NAME = "Package table"; const VULN_TABLE_NAME = "Vulnerability table"; -Given( - "An ingested {string} SBOM {string} is available", - async ({ page }, _sbomType, sbomName) => { - const searchPage = new SearchPage(page); - await searchPage.dedicatedSearch("SBOMs", sbomName); - } -); +Given("An ingested SBOM {string} is available", async ({ page }, sbomName) => { + const searchPage = new SearchPage(page, "SBOMs"); + await searchPage.dedicatedSearch(sbomName); +}); When( "User visits SBOM details Page of {string}", @@ -83,10 +80,10 @@ Then( ); Given( - "An ingested {string} SBOM {string} containing Vulnerabilities", - async ({ page }, _sbomType, sbomName) => { - const searchPage = new SearchPage(page); - await searchPage.dedicatedSearch("SBOMs", sbomName); + "An ingested SBOM {string} containing Vulnerabilities", + async ({ page }, sbomName) => { + const searchPage = new SearchPage(page, "SBOMs"); + await searchPage.dedicatedSearch(sbomName); const element = await page.locator( `xpath=(//tr[contains(.,'${sbomName}')]/td[@data-label='Vulnerabilities']/div)[1]` ); @@ -149,10 +146,10 @@ Then( ); Then( - "List of related Vulnerabilities should be sorted by {string} in descending order", + "List of related Vulnerabilities should be sorted by {string} in ascending order", async ({ page }, columnName) => { const toolbarTable = new ToolbarTable(page, VULN_TABLE_NAME); - await toolbarTable.verifyTableIsSortedBy(columnName, false); + await toolbarTable.verifyTableIsSortedBy(columnName, true); } ); @@ -167,3 +164,26 @@ Then("Pagination of Packages list works", async ({ page }) => { const vulnTableTopPagination = `xpath=//div[@id="package-table-pagination-top"]`; await toolbarTable.verifyPagination(vulnTableTopPagination); }); + +Then( + "List of Vulnerabilities has column {string}", + async ({ page }, columnHeader) => { + const toolbarTable = new ToolbarTable(page, VULN_TABLE_NAME); + await toolbarTable.verifyTableHeaderContains(columnHeader); + } +); + +Then( + "Table column {string} is not sortable", + async ({ page }, columnHeader) => { + const toolbarTable = new ToolbarTable(page, VULN_TABLE_NAME); + await toolbarTable.verifyColumnIsNotSortable(columnHeader); + } +); + +Then("Sorting of {string} Columns Works", async ({ page }, columnHeaders) => { + const headers = columnHeaders.split(`,`).map((column) => column.trim()); + const toolbarTable = new ToolbarTable(page, VULN_TABLE_NAME); + const vulnTableTopPagination = `xpath=//div[@id="vulnerability-table-pagination-top"]`; + await toolbarTable.verifySorting(vulnTableTopPagination, headers); +}); diff --git a/tests/ui/features/@vulnerability-explorer/vulnerability-explorer.step.ts b/tests/ui/features/@vulnerability-explorer/vulnerability-explorer.step.ts index 3f5a0ad..5c79307 100644 --- a/tests/ui/features/@vulnerability-explorer/vulnerability-explorer.step.ts +++ b/tests/ui/features/@vulnerability-explorer/vulnerability-explorer.step.ts @@ -10,8 +10,8 @@ const ADVISORY_TABLE_NAME = "Advisory table"; Given( "User visits Vulnerability details Page of {string}", async ({ page }, vulnerabilityID) => { - const searchPage = new SearchPage(page); - await searchPage.dedicatedSearch("Vulnerabilities", vulnerabilityID); + const searchPage = new SearchPage(page, "Vulnerabilities"); + await searchPage.dedicatedSearch(vulnerabilityID); await page.getByRole("link", { name: vulnerabilityID }).click(); } ); diff --git a/tests/ui/helpers/SearchPage.ts b/tests/ui/helpers/SearchPage.ts index cf82a0d..e41bb8c 100644 --- a/tests/ui/helpers/SearchPage.ts +++ b/tests/ui/helpers/SearchPage.ts @@ -3,9 +3,11 @@ import { DetailsPage } from "./DetailsPage"; export class SearchPage { page: Page; + menu: String; - constructor(page: Page) { + constructor(page: Page, menu: String) { this.page = page; + this.menu = menu; } /** @@ -13,9 +15,9 @@ export class SearchPage { * @param menu Option from Vertical navigation menu * @param data Search data to filter */ - async dedicatedSearch(menu: string, data: string) { + async dedicatedSearch(data: string) { await this.page.goto("/"); - await this.page.getByRole("link", { name: menu }).click(); + await this.page.getByRole("link", { name: `${this.menu}` }).click(); const detailsPage = new DetailsPage(this.page); await detailsPage.waitForData(); await detailsPage.verifyDataAvailable(); diff --git a/tests/ui/helpers/ToolbarTable.ts b/tests/ui/helpers/ToolbarTable.ts index 49e51b3..d40c4fb 100644 --- a/tests/ui/helpers/ToolbarTable.ts +++ b/tests/ui/helpers/ToolbarTable.ts @@ -1,4 +1,5 @@ -import { expect, Page } from "@playwright/test"; +import { expect, Locator, Page } from "@playwright/test"; +import { fail } from "assert"; export class ToolbarTable { private _page: Page; private _tableName: string; @@ -59,16 +60,10 @@ export class ToolbarTable { * And bottom section `//div[@id="vulnerability-table-pagination-bottom"]` */ async verifyPagination(parentElem: string) { - const section = this._page.locator(parentElem); const perPageValues = [10, 20, 50, 100]; const totalRows = await this.getTotalRowsFromPagination(parentElem); for (const value of perPageValues) { - const firstPage = section.getByRole("button", { - name: "Go to first page", - }); - if (await firstPage.isEnabled()) { - await firstPage.click(); - } + await this.goToFirstPage(parentElem); let expectedPagecount = Math.trunc(totalRows / value); let remainingRows = totalRows % value; if (remainingRows > 0) { @@ -113,16 +108,7 @@ export class ToolbarTable { * @returns total row count from pagination dropdown */ async getTotalRowsFromPagination(parentElem: string): Promise { - const tableError = this._page.locator( - `xpath=(//tbody[@aria-label="Table error"])[1]` - ); - if (await tableError.isVisible()) { - await expect(tableError, "No Data available").not.toBeVisible(); - } - const progressBar = this._page.getByRole("gridcell", { - name: "Loading...", - }); - await progressBar.waitFor({ state: "hidden", timeout: 5000 }); + await this.waitForTableContent(); const pagination = this._page.locator(parentElem); const totalResultsText = await pagination .locator(`xpath=//button//b[not(contains (.,'-'))]`) @@ -204,7 +190,8 @@ export class ToolbarTable { } /** - * + * Verifies the Pagination Row Count + * Example, in pagination counter `1-10 of 61` - it verifies the @param expMinCount equals to 1 and @param expMaxCount equals to 10 * @param parentElem required to differentiate top and bottom pagination * @param expMinCount Expected Min count on the counter * @param expMaxCount Expected Max count on the counter @@ -226,6 +213,211 @@ export class ToolbarTable { await expect(max).toEqual(expMaxCount); } + /** + * Verifies the columnHeader given is visible + * @param columnHeader Table Column Header + */ + async verifyTableHeaderContains(columnHeader: string) { + const table = this.getTable(); + await table.getByRole("columnheader", { name: columnHeader }).isVisible(); + } + + /** + * Verifies the given Table header doesn't have sortable attribute + * @param columnHeader Table Column Header + */ + async verifyColumnIsNotSortable(columnHeader: string) { + //const table = this.getTable(); + const elem = await this._page.getByRole("columnheader", { + name: `${columnHeader}`, + }); + await elem.click(); + await expect(elem).not.toHaveAttribute("aria-label"); + } + + /** + * Navigate to the First page of the WebTable + * @param parentElem ParentElement to identify Pagination + */ + async goToFirstPage(parentElem: string) { + const firstPage = this._page.locator(parentElem).getByRole("button", { + name: "Go to first page", + }); + if (await firstPage.isEnabled()) { + await firstPage.click(); + } + } + + /** + * Wait for Table data - Check for Table Error not occurs and Wait for 5000ms + */ + async waitForTableContent() { + const tableError = this._page.locator( + `xpath=(//tbody[@aria-label="Table error"])[1]` + ); + if (await tableError.isVisible()) { + await expect(tableError, "No Data available").not.toBeVisible(); + } + const progressBar = this._page.getByRole("gridcell", { + name: "Loading...", + }); + await progressBar.waitFor({ state: "hidden", timeout: 10000 }); + } + + /** + * Retrieve Table header and Row values in array + * @param parentElem ParentElement of pagination + * @returns two dimensional string which contains the contents of table + */ + async getTableRows(parentElem: string): Promise { + const nextPageElem = await this._page + .locator(parentElem) + .getByLabel("Go to next page"); + let isNextPageEnabled = true; + const tableData: string[][] = []; + await this.goToFirstPage(parentElem); + while (isNextPageEnabled) { + const vuln_table = await this.getTable(); + const allRows = await vuln_table.locator(`tr`).all(); + for (const row of allRows) { + const rowData = await row.locator(`th, td`).allTextContents(); + tableData.push(rowData); + } + isNextPageEnabled = await nextPageElem.isEnabled(); + } + return tableData; + } + + /** + * Sort table for the given column index and sorting order + * @param table Source table for Sorting + * @param header Target header to be sorted + * @param sorting sorting order + * @returns tow dimensional array containing sorted table based on the given column in given sorting order + */ + async sortTable( + table: string[][], + header: string, + sorting: string = `ascending` + ): Promise { + const headerRow = table[0]; + const dataRow = table.slice(1); + const index = headerRow.indexOf(header); + let row = 0; + if (index < 0) { + fail("Given header not found"); + } + for (const data of dataRow) { + if (data[index] !== ``) { + row += 1; + break; + } + } + let isDate = this.isValidDate(dataRow[row][index]); + let isCVSS = this.isCVSS(dataRow[row][index]); + const sortedRows = [...dataRow].sort((rowA, rowB) => { + let compare: any; + const valueA = rowA[index]; + const valueB = rowB[index]; + if (isDate) { + const dateA = new Date(valueA); + const dateB = new Date(valueB); + compare = dateA.getTime() - dateB.getTime(); + } else if (isCVSS) { + const cvssA = this.getCVSS(valueA); + const cvssB = this.getCVSS(valueB); + compare = cvssA - cvssB; + } else { + compare = valueA.localeCompare(valueB); + } + + if (sorting == "descending") { + compare *= -1; + } + return compare; + }); + return [headerRow, ...sortedRows]; + } + + /** + * To verify the given string is in Date format + * @param dateString Input date value + * @returns true if the given input is date + */ + isValidDate(dateString: string): boolean { + const validDate = new Date(dateString); + return !isNaN(validDate.getTime()); + } + + /** + * To verify the given string is in CVSS format + * @param cvssString input CVSS value + * @returns true if the given input is in CVSS format + */ + isCVSS(cvssString: string): boolean { + const cvssRegex = /^.+\((\d*\.*\d+?)\)$/; + return cvssRegex.test(cvssString) ? true : false; + } + + /** + * To retrieve CVSS score from the given string + * @param cvssString input CVSS value + * @returns CVSS score if the given input is in CVSS format + */ + getCVSS(cvssString: string): number { + const cvssRegex = /^.+\((\d*\.*\d+?)\)$/; + let cvssScore = cvssString.match(cvssRegex)!; + return parseFloat(cvssScore[1]!); + } + + /** + * To sort a column for the given order + * @param columnHeader column Name + * @param sortOrder Sorting order Ascending or descending + * @returns Boolean based on whether column sorted with expected order + */ + async sortColumn(columnHeader: string, sortOrder: string): Promise { + const headerElem = await this._page.getByRole("columnheader", { + name: `${columnHeader}`, + }); + for (let i = 0; i < 3; i++) { + const sort = await headerElem.getAttribute(`aria-sort`); + if (sort === sortOrder) { + return true; + } else { + await headerElem.click(); + } + } + return false; + } + + /** + * Verifies Sorting of given Columns in Ascending and Descending orders + * @param parentElem ParentElement for Pagination + * @param columnHeaders List of column headers to be verified + */ + async verifySorting(parentElem: string, columnHeaders: string[]) { + const perPageValue = "100"; + await this.waitForTableContent(); + await this.selectPerPage(parentElem, perPageValue); + for (let header of columnHeaders) { + for (let order of [`ascending`, `descending`]) { + const sorted = await this.sortColumn(header, order); + sorted? null: (() => { + throw new Error( + `Sorting failed for the column ${header} with order ${order}` + ); + })(); + let sourceData = await this.getTableRows(parentElem); + let sortedData = await this.sortTable(await sourceData, header, order); + await expect( + sourceData, + `Column ${header} sorting ${order} order` + ).toEqual(sortedData); + } + } + } + private getTable() { return this._page.locator(`table[aria-label="${this._tableName}"]`); } From 65e551fe5aa135d7ef9a1cd8b069e957b90bdec2 Mon Sep 17 00:00:00 2001 From: mrrajan <86094767+mrrajan@users.noreply.github.com.> Date: Mon, 9 Jun 2025 19:44:06 +0530 Subject: [PATCH 2/5] Formatting changes Signed-off-by: mrrajan <86094767+mrrajan@users.noreply.github.com.> --- tests/ui/helpers/ToolbarTable.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui/helpers/ToolbarTable.ts b/tests/ui/helpers/ToolbarTable.ts index d40c4fb..4b3674d 100644 --- a/tests/ui/helpers/ToolbarTable.ts +++ b/tests/ui/helpers/ToolbarTable.ts @@ -403,7 +403,9 @@ export class ToolbarTable { for (let header of columnHeaders) { for (let order of [`ascending`, `descending`]) { const sorted = await this.sortColumn(header, order); - sorted? null: (() => { + sorted + ? null + : (() => { throw new Error( `Sorting failed for the column ${header} with order ${order}` ); From 919540be0768403e39ba2b73f1d5bd6e4e48eab0 Mon Sep 17 00:00:00 2001 From: mrrajan <86094767+mrrajan@users.noreply.github.com.> Date: Tue, 10 Jun 2025 12:28:22 +0530 Subject: [PATCH 3/5] Comparing logic for CVE Signed-off-by: mrrajan <86094767+mrrajan@users.noreply.github.com.> --- tests/ui/helpers/ToolbarTable.ts | 40 ++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/tests/ui/helpers/ToolbarTable.ts b/tests/ui/helpers/ToolbarTable.ts index 4b3674d..eb9fb36 100644 --- a/tests/ui/helpers/ToolbarTable.ts +++ b/tests/ui/helpers/ToolbarTable.ts @@ -315,18 +315,23 @@ export class ToolbarTable { } let isDate = this.isValidDate(dataRow[row][index]); let isCVSS = this.isCVSS(dataRow[row][index]); + let isCVE = this.isCVE(dataRow[row][index]); const sortedRows = [...dataRow].sort((rowA, rowB) => { let compare: any; - const valueA = rowA[index]; - const valueB = rowB[index]; + let valueA = rowA[index]; + let valueB = rowB[index]; if (isDate) { - const dateA = new Date(valueA); - const dateB = new Date(valueB); + let dateA = new Date(valueA); + let dateB = new Date(valueB); compare = dateA.getTime() - dateB.getTime(); } else if (isCVSS) { - const cvssA = this.getCVSS(valueA); - const cvssB = this.getCVSS(valueB); + let cvssA = this.getCVSS(valueA); + let cvssB = this.getCVSS(valueB); compare = cvssA - cvssB; + } else if (isCVE) { + let [cveYA, cveIA] = this.getCVE(valueA); + let [cveYB, cveIB] = this.getCVE(valueB); + compare = cveYA !== cveYB ? cveYA - cveYB : cveIA - cveIB; } else { compare = valueA.localeCompare(valueB); } @@ -359,6 +364,16 @@ export class ToolbarTable { return cvssRegex.test(cvssString) ? true : false; } + /** + * To verify the given string is in CVE format + * @param cve input CVSS value + * @returns true if the given input is in CVE format + */ + isCVE(cve: string): boolean { + const cveRegex = /^CVE-(\d+?)-(\d+?)$/; + return cveRegex.test(cve) ? true : false; + } + /** * To retrieve CVSS score from the given string * @param cvssString input CVSS value @@ -370,6 +385,17 @@ export class ToolbarTable { return parseFloat(cvssScore[1]!); } + /** + * To retrieve CVE year and ID from the given string + * @param cve input CVE value + * @returns CVE Year and ID if the given input is in CVE format + */ + getCVE(cve: string): [number, number] { + const matchCVE = cve.match(/^CVE-(\d+)-(\d+)$/); + if (!matchCVE) throw new Error(`Invalid CVE format: ${cve}`); + return [Number(matchCVE[1]), Number(matchCVE[2])]; + } + /** * To sort a column for the given order * @param columnHeader column Name @@ -385,7 +411,7 @@ export class ToolbarTable { if (sort === sortOrder) { return true; } else { - await headerElem.click(); + await headerElem.getByRole("button").click(); } } return false; From 4b9f37e6bafe7b61c8ab8128c03de208225144b6 Mon Sep 17 00:00:00 2001 From: mrrajan <86094767+mrrajan@users.noreply.github.com.> Date: Mon, 30 Jun 2025 17:58:43 +0530 Subject: [PATCH 4/5] Naming and parameter changes Signed-off-by: mrrajan <86094767+mrrajan@users.noreply.github.com.> --- .../@sbom-explorer/sbom-explorer.feature | 34 +++++++++---------- tests/ui/helpers/ToolbarTable.ts | 9 +++-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/tests/ui/features/@sbom-explorer/sbom-explorer.feature b/tests/ui/features/@sbom-explorer/sbom-explorer.feature index 95444a8..8c6d55a 100644 --- a/tests/ui/features/@sbom-explorer/sbom-explorer.feature +++ b/tests/ui/features/@sbom-explorer/sbom-explorer.feature @@ -59,10 +59,10 @@ Feature: SBOM Explorer - View SBOM details Then The Package table total results is greather than 1 Examples: - | sbomType | sbomName | packageName | - | SPDX | quarkus-bom | jdom | + | sbomName | packageName | + | quarkus-bom | jdom | - Scenario Outline: View SBOM Vulnerabilities + Scenario Outline: View SBOM Vulnerabilities Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" @@ -76,30 +76,30 @@ Feature: SBOM Explorer - View SBOM details Then List of related Vulnerabilities should be sorted by "Id" in ascending order Examples: - | sbomType | sbomName | - | SPDX | quarkus-bom | + | sbomName | + | quarkus-bom | @slow - Scenario Outline: Pagination of SBOM Vulnerabilities + Scenario Outline: Pagination of SBOM Vulnerabilities table Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" Then Pagination of Vulnerabilities list works Examples: - | sbomType | sbomName | - | SPDX | quarkus-bom | + | sbomName | + | quarkus-bom | @slow - Scenario Outline: View paginated list of SBOM Packages + Scenario Outline: View paginated list of SBOM Packages Given An ingested SBOM "" is available When User visits SBOM details Page of "" When User selects the Tab "Packages" Then Pagination of Packages list works Examples: - | sbomType | sbomName | - | SPDX | quarkus-bom | + | sbomName | + | quarkus-bom | - Scenario Outline: Columns in list of SBOM Vulnerabilities + Scenario Outline: Check Column Headers of SBOM Explorer Vulnerabilities table Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" @@ -110,11 +110,11 @@ Feature: SBOM Explorer - View SBOM details Then List of Vulnerabilities has column "Published" Then List of Vulnerabilities has column "Updated" Examples: - | sbomType | sbomName | - | SPDX | quarkus-bom | + | sbomName | + | quarkus-bom | @slow - Scenario Outline: Sorting SBOM Vulnerabilities + Scenario Outline: Sorting SBOM Vulnerabilities Given An ingested SBOM "" containing Vulnerabilities When User visits SBOM details Page of "" When User selects the Tab "Vulnerabilities" @@ -123,5 +123,5 @@ Feature: SBOM Explorer - View SBOM details #Then Sorting of "CVSS" Columns works # Bug: https://issues.redhat.com/browse/TC-2598 Examples: - | sbomType | sbomName | - | SPDX | quarkus-bom | \ No newline at end of file + | sbomName | + | quarkus-bom | \ No newline at end of file diff --git a/tests/ui/helpers/ToolbarTable.ts b/tests/ui/helpers/ToolbarTable.ts index eb9fb36..703e171 100644 --- a/tests/ui/helpers/ToolbarTable.ts +++ b/tests/ui/helpers/ToolbarTable.ts @@ -277,8 +277,8 @@ export class ToolbarTable { const tableData: string[][] = []; await this.goToFirstPage(parentElem); while (isNextPageEnabled) { - const vuln_table = await this.getTable(); - const allRows = await vuln_table.locator(`tr`).all(); + const table_data = await this.getTable(); + const allRows = await table_data.locator(`tr`).all(); for (const row of allRows) { const rowData = await row.locator(`th, td`).allTextContents(); tableData.push(rowData); @@ -422,10 +422,9 @@ export class ToolbarTable { * @param parentElem ParentElement for Pagination * @param columnHeaders List of column headers to be verified */ - async verifySorting(parentElem: string, columnHeaders: string[]) { - const perPageValue = "100"; + async verifySorting(parentElem: string, columnHeaders: string[], perPageCount: string = "100") { await this.waitForTableContent(); - await this.selectPerPage(parentElem, perPageValue); + await this.selectPerPage(parentElem, perPageCount); for (let header of columnHeaders) { for (let order of [`ascending`, `descending`]) { const sorted = await this.sortColumn(header, order); From 61da9728288178336de72195fc96bbd0d55422a3 Mon Sep 17 00:00:00 2001 From: mrrajan <86094767+mrrajan@users.noreply.github.com.> Date: Mon, 30 Jun 2025 18:02:18 +0530 Subject: [PATCH 5/5] formatting and prettier Signed-off-by: mrrajan <86094767+mrrajan@users.noreply.github.com.> --- tests/ui/helpers/ToolbarTable.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ui/helpers/ToolbarTable.ts b/tests/ui/helpers/ToolbarTable.ts index 703e171..b66b0d5 100644 --- a/tests/ui/helpers/ToolbarTable.ts +++ b/tests/ui/helpers/ToolbarTable.ts @@ -422,7 +422,11 @@ export class ToolbarTable { * @param parentElem ParentElement for Pagination * @param columnHeaders List of column headers to be verified */ - async verifySorting(parentElem: string, columnHeaders: string[], perPageCount: string = "100") { + async verifySorting( + parentElem: string, + columnHeaders: string[], + perPageCount: string = "100" + ) { await this.waitForTableContent(); await this.selectPerPage(parentElem, perPageCount); for (let header of columnHeaders) {