-
Notifications
You must be signed in to change notification settings - Fork 37
Add LicenseExport feature CDX tests #942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
a-oren
wants to merge
2
commits into
guacsec:main
Choose a base branch
from
a-oren:tests/license-explorer
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
e2e/tests/ui/features/@license-export_cdx/license-export_cdx.feature
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| Feature: License Explorer | ||
| As a Platform Eng | ||
| I want to be able to download the licenses in a CSV file format from a specific SBOM | ||
|
|
||
| Background: | ||
|
|
||
| Scenario: Verify Download Licences option on SBOM Search Results page for CycloneDX SBOM | ||
| Given User Searches for CycloneDX SBOM "<sbomName>" using Search Text box | ||
| When User Selects CycloneDX SBOM "<sbomName>" from the Search Results | ||
| And User Clicks on SBOM name hyperlink from the Search Results | ||
| And User Clicks "Action" button | ||
| Then "Download License Report" Option should be visible | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario Outline: User Downloads license information for CycloneDX SBOM from SBOM Search Results page | ||
| Given User Searches for CycloneDX SBOM "<sbomName>" using Search Text box | ||
| When User Selects CycloneDX SBOM "<sbomName>" from the Search Results | ||
| And User Clicks on SBOM name hyperlink from the Search Results | ||
| And User Clicks "Action" button | ||
| And Selects "Download License Report" option | ||
| Then Licenses associated with the SBOM should be downloaded in TAR.GZ format using the SBOM name | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: Verify Download Licences option on SBOM Explorer page for CycloneDX SBOM | ||
| Given User Searches for CycloneDX SBOM "<sbomName>" using Search Text box and Navigates to Search results page | ||
| When User Selects CycloneDX SBOM "<sbomName>" from the Search Results | ||
| And User Clicks on SBOM name hyperlink from the Search Results | ||
| Then Application Navigates to SBOM Explorer page | ||
| And User Clicks "Action" button | ||
| And "Download License Report" Option should be visible | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: User Downloads license information for CycloneDX SBOM from SBOM Explorer page | ||
| Given User is on SBOM Explorer page for the CycloneDX SBOM "<sbomName>" | ||
| And User Clicks on "Download License Report" button | ||
| Then Licenses associated with the SBOM should be downloaded in TAR.GZ format using the SBOM name | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: Verify the files on downloaded CycloneDX SBOM license TAR.GZ | ||
| Given User has Downloaded the License information for CycloneDX SBOM "<sbomName>" | ||
| When User extracts the Downloaded license TAR.GZ file | ||
| Then Extracted files should contain two CSVs, one for Package license information and another one for License reference | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: Verify the headers on CycloneDX SBOM package License CSV file | ||
| Given User extracted the CycloneDX SBOM "<sbomName>" license compressed file | ||
| When User Opens the package license information file | ||
| Then The file should have the following headers - SBOM name, SBOM id, package name, package group, package version, package purl, package cpe and license | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: Verify the headers on CycloneDX SBOM License reference CSV file | ||
| Given User extracted the CycloneDX SBOM "<sbomName>" license compressed file | ||
| When User Opens the license reference file | ||
| Then The file should have the following headers - licenseId, name, extracted text and comment | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | | ||
|
|
||
| Scenario: Verify the contents on CycloneDX SBOM license reference CSV file | ||
| Given User is on license reference "<sbomName>" file | ||
| Then The License reference CSV should be empty | ||
|
|
||
| Examples: | ||
| | sbomName | | ||
| | liboqs | |
205 changes: 205 additions & 0 deletions
205
e2e/tests/ui/features/@license-export_cdx/license-export_cdx.step.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| import { createBdd } from "playwright-bdd"; | ||
| import * as fs from "node:fs"; | ||
|
|
||
| import { test } from "../../fixtures"; | ||
|
|
||
| import { expect } from "../../assertions"; | ||
|
|
||
| import { SbomListPage } from "../../pages/sbom-list/SbomListPage"; | ||
| import { SbomDetailsPage } from "../../pages/sbom-details/SbomDetailsPage"; | ||
| import { DetailsPage } from "../../helpers/DetailsPage"; | ||
| import { SearchPage } from "../../helpers/SearchPage"; | ||
| import { clickAndVerifyDownload } from "../../pages/Helpers"; | ||
| import { | ||
| downloadLicenseReport, | ||
| extractLicenseReport, | ||
| findCsvWithHeader, | ||
| } from "../../pages/LicenseExportHelpers"; | ||
|
|
||
| export const { Given, When, Then } = createBdd(test); | ||
|
|
||
| let downloadedFilename: string; | ||
| let downloadedFilePath: string; | ||
| let extractionPath: string; | ||
| let packageLicenseFilePath: string; | ||
| let licenseReferenceFilePath: string; | ||
|
|
||
| Given( | ||
| "User Searches for CycloneDX SBOM {string} using Search Text box", | ||
| async ({ page }, sbomName: string) => { | ||
| const listPage = await SbomListPage.build(page); | ||
| const toolbar = await listPage.getToolbar(); | ||
| await toolbar.applyFilter({ "Filter text": sbomName }); | ||
| }, | ||
| ); | ||
|
|
||
| Given( | ||
| "User Searches for CycloneDX SBOM {string} using Search Text box and Navigates to Search results page", | ||
| async ({ page }, sbomName: string) => { | ||
| const searchPage = new SearchPage(page, "Search"); | ||
| await searchPage.generalSearch("SBOMs", sbomName); | ||
| }, | ||
| ); | ||
|
|
||
| When( | ||
| "User Selects CycloneDX SBOM {string} from the Search Results", | ||
| async ({ page }, sbomName: string) => { | ||
| const listPage = await SbomListPage.fromCurrentPage(page); | ||
| const table = await listPage.getTable(); | ||
| await table.waitUntilDataIsLoaded(); | ||
|
|
||
| await expect(table).toHaveColumnWithValue("Name", sbomName); | ||
| }, | ||
| ); | ||
|
|
||
| When( | ||
| "User Clicks on SBOM name hyperlink from the Search Results", | ||
| async ({ page }) => { | ||
| const listPage = await SbomListPage.fromCurrentPage(page); | ||
| const table = await listPage.getTable(); | ||
| const rows = await table.getRows(); | ||
| await rows.first().getByRole("link").click(); | ||
| }, | ||
| ); | ||
|
|
||
| Then("Application Navigates to SBOM Explorer page", async ({ page }) => { | ||
| await expect(page).toHaveURL(/\/sboms\/[^/]+/); | ||
| }); | ||
|
|
||
| When('User Clicks "Action" button', async ({ page }) => { | ||
| const detailsPage = new DetailsPage(page); | ||
| await detailsPage.openActionsMenu(); | ||
| }); | ||
|
|
||
| Then('"Download License Report" Option should be visible', async ({ page }) => { | ||
| const detailsPage = new DetailsPage(page); | ||
| await detailsPage.verifyActionIsVisibleInMenu("Download License Report"); | ||
| }); | ||
|
|
||
| When('Selects "Download License Report" option', async ({ page }) => { | ||
| const detailsPage = new DetailsPage(page); | ||
| downloadedFilename = await clickAndVerifyDownload( | ||
| page, | ||
| async () => | ||
| await detailsPage.page | ||
| .getByRole("menuitem", { name: "Download License Report" }) | ||
| .click(), | ||
| ); | ||
| }); | ||
|
|
||
| Then( | ||
| "Licenses associated with the SBOM should be downloaded in TAR.GZ format using the SBOM name", | ||
| async ({ page }) => { | ||
| const sbomName = await page.getByRole("heading").first().innerText(); | ||
| expect(downloadedFilename).toContain(sbomName); | ||
| expect(downloadedFilename.endsWith(".tar.gz")).toBeTruthy(); | ||
| }, | ||
| ); | ||
|
|
||
| Given( | ||
| "User is on SBOM Explorer page for the CycloneDX SBOM {string}", | ||
| async ({ page }, sbomName: string) => { | ||
| await SbomDetailsPage.build(page, sbomName); | ||
| }, | ||
| ); | ||
|
|
||
| When('User Clicks on "Download License Report" button', async ({ page }) => { | ||
| const detailsPage = new DetailsPage(page); | ||
| await detailsPage.openActionsMenu(); | ||
|
|
||
| downloadedFilename = await clickAndVerifyDownload( | ||
| page, | ||
| async () => | ||
| await detailsPage.page | ||
| .getByRole("menuitem", { name: "Download License Report" }) | ||
| .click(), | ||
| ); | ||
| }); | ||
|
|
||
| Given( | ||
| "User has Downloaded the License information for CycloneDX SBOM {string}", | ||
| async ({ page }, sbomName: string) => { | ||
| await SbomDetailsPage.build(page, sbomName); | ||
| downloadedFilePath = await downloadLicenseReport(page); | ||
| }, | ||
| ); | ||
|
|
||
| When("User extracts the Downloaded license TAR.GZ file", async () => { | ||
| extractionPath = await extractLicenseReport(downloadedFilePath); | ||
| }); | ||
|
|
||
| Then( | ||
| "Extracted files should contain two CSVs, one for Package license information and another one for License reference", | ||
| async () => { | ||
| const files = fs.readdirSync(extractionPath); | ||
| const csvFiles = files.filter((file) => file.endsWith(".csv")); | ||
| expect(csvFiles.length).toBe(2); | ||
| }, | ||
| ); | ||
|
|
||
| Given( | ||
| "User extracted the CycloneDX SBOM {string} license compressed file", | ||
| async ({ page }, sbomName: string) => { | ||
| await SbomDetailsPage.build(page, sbomName); | ||
| downloadedFilePath = await downloadLicenseReport(page); | ||
| extractionPath = await extractLicenseReport(downloadedFilePath); | ||
| }, | ||
| ); | ||
|
|
||
| When("User Opens the package license information file", async () => { | ||
| packageLicenseFilePath = findCsvWithHeader( | ||
| extractionPath, | ||
| "SBOM name", | ||
| "Package license information file", | ||
| ); | ||
| }); | ||
|
|
||
| Then( | ||
| "The file should have the following headers - SBOM name, SBOM id, package name, package group, package version, package purl, package cpe and license", | ||
| async () => { | ||
| const content = fs.readFileSync(packageLicenseFilePath, "utf-8"); | ||
| const headers = content.split("\n")[0].trim(); | ||
| const expectedHeaders = | ||
| '"SBOM name"\t"SBOM id"\t"package name"\t"package group"\t"package version"\t"package purl"\t"package cpe"\t"license"\t"license type"'; | ||
| expect(headers).toBe(expectedHeaders); | ||
| }, | ||
| ); | ||
|
|
||
| When("User Opens the license reference file", async () => { | ||
| licenseReferenceFilePath = findCsvWithHeader( | ||
| extractionPath, | ||
| "licenseId", | ||
| "License reference file", | ||
| ); | ||
| }); | ||
|
|
||
| Then( | ||
| "The file should have the following headers - licenseId, name, extracted text and comment", | ||
| async () => { | ||
| const content = fs.readFileSync(licenseReferenceFilePath, "utf-8"); | ||
| const headers = content.split("\n")[0].trim(); | ||
| const expectedHeaders = '"licenseId"\t"name"\t"extracted text"\t"comment"'; | ||
| expect(headers).toBe(expectedHeaders); | ||
| }, | ||
| ); | ||
|
|
||
| Given( | ||
| "User is on license reference {string} file", | ||
| async ({ page }, sbomName: string) => { | ||
| await SbomDetailsPage.build(page, sbomName); | ||
| downloadedFilePath = await downloadLicenseReport(page); | ||
| extractionPath = await extractLicenseReport(downloadedFilePath); | ||
| licenseReferenceFilePath = findCsvWithHeader( | ||
| extractionPath, | ||
| "licenseId", | ||
| "License reference file", | ||
| ); | ||
| }, | ||
| ); | ||
|
|
||
| Then("The License reference CSV should be empty", async () => { | ||
| const content = fs.readFileSync(licenseReferenceFilePath, "utf-8"); | ||
| const lines = content.trim().split("\n"); | ||
| // Only header should be present | ||
| expect(lines.length).toBe(1); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the
verifyActionIsVisibleInMenunow deals only with verification part and user actions is underopenActionsMenu. Which is good comparing to,verifyActionIsAvailable. But shall we move the verification part into assertions? This ensures type safety and consistency.