# Instructions - Following Playwright test failed. - Explain why, be concise, respect Playwright best practices. - Provide a snippet of code with the fix, if possible. # Test info - Name: ui/component.test.ts >> Component UI Test Suite >> Verify CI >> verify CI provider on CI tab - Location: tests/ui/component.test.ts:83:5 # Error details ``` TimeoutError: Step timeout of 40000ms exceeded. ``` ``` Error: expect(locator).toBeVisible() failed Locator: getByText('STEP-SHOW-SBOM') Expected: visible Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 60000ms - waiting for getByText('STEP-SHOW-SBOM') ``` # Page snapshot ```yaml - generic [ref=e1]: - generic [ref=e3]: - navigation [ref=e5]: - generic [ref=e6]: - link [ref=e8] [cursor=pointer]: - /url: / - img [ref=e9] - generic [ref=e18]: - img [ref=e20] - combobox [ref=e22] - link [ref=e26] [cursor=pointer]: - /url: /create - img [ref=e28] - button [ref=e31] [cursor=pointer]: - img [ref=e32] - button [ref=e35] [cursor=pointer]: - img [ref=e36] - button [ref=e39] [cursor=pointer]: - img [ref=e40] - separator [ref=e42] - button [ref=e44] [cursor=pointer]: - generic [ref=e45]: - img [ref=e46] - paragraph [ref=e49]: Admin - img [ref=e50] - generic [ref=e53]: - generic [ref=e55]: - generic [ref=e58]: - link [ref=e60] [cursor=pointer]: - /url: / - img [ref=e64] - generic [ref=e66]: Home - link [ref=e68] [cursor=pointer]: - /url: /catalog - img [ref=e72] - generic [ref=e74]: Catalog - link [ref=e76] [cursor=pointer]: - /url: /api-docs - img [ref=e80] - generic [ref=e82]: APIs - link [ref=e84] [cursor=pointer]: - /url: /learning-paths - img [ref=e88] - generic [ref=e90]: Learning Paths - separator [ref=e91] - link [ref=e94] [cursor=pointer]: - /url: /docs - img [ref=e98] - generic [ref=e100]: Docs - generic [ref=e101]: - separator [ref=e102] - button [ref=e103] [cursor=pointer]: - generic [ref=e104]: - img [ref=e108] - generic [ref=e111]: Administration - img [ref=e113] - main [ref=e115]: - generic [ref=e116]: - generic [ref=e117]: - paragraph [ref=e118]: component — service - heading [level=1] [ref=e119]: - generic [ref=e120]: - generic [ref=e122]: e2e-tests-go-nbuztanv - button [ref=e123] [cursor=pointer]: - img [ref=e126] - generic [ref=e128]: - generic [ref=e130]: - paragraph [ref=e131]: Owner - paragraph [ref=e132]: - link [ref=e133] [cursor=pointer]: - /url: /catalog/default/user/guest - generic [ref=e134]: - img [ref=e136] - text: user:guest - generic [ref=e139]: - paragraph [ref=e140]: Lifecycle - paragraph [ref=e141]: experimental - button [ref=e142] [cursor=pointer]: - img [ref=e144] - tablist [ref=e150]: - tab [ref=e151] [cursor=pointer]: Overview - tab [ref=e152] [cursor=pointer]: Topology - tab [selected] [ref=e153] [cursor=pointer]: CI - tab [ref=e154] [cursor=pointer]: CD - tab [ref=e155] [cursor=pointer]: Kubernetes - tab [ref=e156] [cursor=pointer]: Image Registry - tab [ref=e157] [cursor=pointer]: API - tab [ref=e158] [cursor=pointer]: Dependencies - tab [ref=e159] [cursor=pointer]: Docs - article [ref=e161]: - generic [ref=e164]: - generic [ref=e168]: - generic [ref=e169]: - paragraph [ref=e170]: Cluster - generic [ref=e173]: - button [ref=e174] [cursor=pointer]: - paragraph [ref=e175]: rhdh-cluster - textbox: rhdh-cluster - img - generic [ref=e176]: - paragraph [ref=e177]: Status - generic [ref=e180]: - button [ref=e181] [cursor=pointer]: - paragraph [ref=e182]: All - textbox: All - img - generic [ref=e183]: - generic [ref=e184]: - button [disabled]: - generic: - img - button [ref=e186] [cursor=pointer]: - img [ref=e188] - separator [ref=e190] - generic [ref=e193]: - generic [ref=e194]: - heading [level=2] [ref=e195]: Pipeline Runs - generic [ref=e197]: - img [ref=e199] - textbox [ref=e201]: - /placeholder: Search - generic [ref=e202]: - button [disabled]: - generic: - img - table [ref=e203]: - rowgroup [ref=e204]: - row [ref=e205]: - columnheader [ref=e206] - columnheader [ref=e207]: - button [ref=e208] [cursor=pointer]: - text: NAME - img [ref=e209] - columnheader [ref=e211]: - button [ref=e212] [cursor=pointer]: - text: VULNERABILITIES - img [ref=e213] - columnheader [ref=e215]: - button [ref=e216] [cursor=pointer]: - text: STATUS - img [ref=e217] - columnheader [ref=e219]: - button [ref=e220] [cursor=pointer]: - text: TASK STATUS - img [ref=e221] - columnheader [ref=e223]: - button [ref=e224] [cursor=pointer]: - text: STARTED - img [ref=e225] - columnheader [ref=e227]: - button [ref=e228] [cursor=pointer]: - text: DURATION - img [ref=e229] - columnheader [ref=e231]: ACTIONS - rowgroup [ref=e232]: - row [ref=e233]: - cell [ref=e234]: - button [ref=e235] [cursor=pointer]: - img [ref=e237] - cell [ref=e239]: - generic [ref=e241]: - generic [ref=e243]: PLR - generic [ref=e244]: e2e-tests-go-nbuztanv-gitops-on-pull-request-r25hn - img [ref=e248] - cell [ref=e251]: - generic [ref=e252]: "-" - cell [ref=e253]: - paragraph [ref=e254]: - img [ref=e257] - generic [ref=e259]: Succeeded - cell [ref=e260] - cell [ref=e261]: - time [ref=e263]: 5/4/2026, 6:15:05 PM - cell [ref=e264]: 49 seconds - cell [ref=e265]: - generic [ref=e266]: - button [ref=e269] [cursor=pointer]: - img [ref=e271] - button [ref=e275] [cursor=pointer]: - img [ref=e277] - button [disabled] [ref=e281]: - img [ref=e283] - button [disabled] [ref=e287]: - img [ref=e289] - row [ref=e291]: - cell [ref=e292] - row [ref=e293]: - cell [ref=e294]: - button [ref=e295] [cursor=pointer]: - img [ref=e297] - cell [ref=e299]: - generic [ref=e301]: - generic [ref=e303]: PLR - generic [ref=e304]: e2e-tests-go-nbuztanv-gitops-on-pull-request-5w5t7 - img [ref=e308] - cell [ref=e311]: - generic [ref=e312]: "-" - cell [ref=e313]: - paragraph [ref=e314]: - img [ref=e317] - generic [ref=e319]: Succeeded - cell [ref=e320] - cell [ref=e321]: - time [ref=e323]: 5/4/2026, 6:13:25 PM - cell [ref=e324]: 46 seconds - cell [ref=e325]: - generic [ref=e326]: - button [ref=e329] [cursor=pointer]: - img [ref=e331] - button [ref=e335] [cursor=pointer]: - img [ref=e337] - button [disabled] [ref=e341]: - img [ref=e343] - button [disabled] [ref=e347]: - img [ref=e349] - row [ref=e351]: - cell [ref=e352] - row [ref=e353]: - cell [ref=e354]: - button [ref=e355] [cursor=pointer]: - img [ref=e357] - cell [ref=e359]: - generic [ref=e361]: - generic [ref=e363]: PLR - generic [ref=e364]: e2e-tests-go-nbuztanv-on-push-mbrzn - img [ref=e368] - cell [ref=e371]: - generic [ref=e372]: - generic [ref=e373]: - img [ref=e376] - generic [ref=e378]: "0" - generic [ref=e379]: - img [ref=e382] - generic [ref=e385]: "3" - generic [ref=e386]: - img [ref=e389] - generic [ref=e391]: "8" - generic [ref=e392]: - img [ref=e395] - generic [ref=e398]: "8" - cell [ref=e399]: - paragraph [ref=e400]: - img [ref=e403] - generic [ref=e405]: Succeeded - cell [ref=e406] - cell [ref=e407]: - time [ref=e409]: 5/4/2026, 6:10:38 PM - cell [ref=e410]: 1 minute 47 seconds - cell [ref=e411]: - generic [ref=e412]: - button [ref=e415] [cursor=pointer]: - img [ref=e417] - button [ref=e421] [cursor=pointer]: - img [ref=e423] - button [ref=e427] [cursor=pointer]: - img [ref=e429] - button [ref=e433] [cursor=pointer]: - img [ref=e435] - row [ref=e437]: - cell [ref=e438] - row [ref=e439]: - cell [ref=e440]: - button [ref=e441] [cursor=pointer]: - img [ref=e443] - cell [ref=e445]: - generic [ref=e447]: - generic [ref=e449]: PLR - generic [ref=e450]: e2e-tests-go-nbuztanv-on-pull-request-f2fvw - img [ref=e454] - cell [ref=e457]: - generic [ref=e458]: - generic [ref=e459]: - img [ref=e462] - generic [ref=e464]: "0" - generic [ref=e465]: - img [ref=e468] - generic [ref=e471]: "3" - generic [ref=e472]: - img [ref=e475] - generic [ref=e477]: "8" - generic [ref=e478]: - img [ref=e481] - generic [ref=e484]: "8" - cell [ref=e485]: - paragraph [ref=e486]: - img [ref=e489] - generic [ref=e491]: Succeeded - cell [ref=e492] - cell [ref=e493]: - time [ref=e495]: 5/4/2026, 6:07:48 PM - cell [ref=e496]: 2 minutes 34 seconds - cell [ref=e497]: - generic [ref=e498]: - button [ref=e501] [cursor=pointer]: - img [ref=e503] - button [ref=e507] [cursor=pointer]: - img [ref=e509] - button [ref=e513] [cursor=pointer]: - img [ref=e515] - button [ref=e519] [cursor=pointer]: - img [ref=e521] - row [ref=e523]: - cell [ref=e524] - row [ref=e525]: - cell [ref=e526]: - generic [ref=e527]: - generic [ref=e528]: - button [ref=e529] [cursor=pointer]: 5 rows - textbox: "5" - img - paragraph [ref=e530]: 1-4 of 4 - generic [ref=e531]: - button [disabled]: - generic: - img - button [disabled]: - generic: - img - dialog [ref=e534]: - generic "PipelineRun Logs" [ref=e535]: - heading "PLR e2e-tests-go-nbuztanv-on-push-mbrzn close" [level=2] [ref=e536]: - generic [ref=e537]: - generic [ref=e538]: - generic [ref=e540]: PLR - generic [ref=e541]: e2e-tests-go-nbuztanv-on-push-mbrzn - button "close" [ref=e542] [cursor=pointer]: - img [ref=e544] - generic [ref=e546]: - generic [ref=e547]: - button "Download" [ref=e549] [cursor=pointer]: - generic [ref=e550]: - img [ref=e551] - text: Download - button "Download all tasks logs" [ref=e554] [cursor=pointer]: - generic [ref=e555]: - img [ref=e556] - text: Download all tasks logs - generic [ref=e558]: - generic [ref=e562]: - button "clone-repository 10s" [ref=e564] [cursor=pointer]: - generic [ref=e565]: - img [ref=e568] - generic [ref=e572]: - heading "clone-repository" [level=6] [ref=e573] - generic [ref=e574]: 10s - button "build 1m 18s" [ref=e578] [cursor=pointer]: - generic [ref=e579]: - img [ref=e582] - generic [ref=e586]: - heading "build" [level=6] [ref=e587] - generic [ref=e588]: 1m 18s - button "deploy 8s" [ref=e592] [cursor=pointer]: - generic [ref=e593]: - img [ref=e596] - generic [ref=e600]: - heading "deploy" [level=6] [ref=e601] - generic [ref=e602]: 8s - button "scan 13s" [ref=e606] [cursor=pointer]: - generic [ref=e607]: - img [ref=e610] - generic [ref=e614]: - heading "scan" [level=6] [ref=e615] - generic [ref=e616]: 13s - button "deployment-check 7s" [ref=e620] [cursor=pointer]: - generic [ref=e621]: - img [ref=e624] - generic [ref=e628]: - heading "deployment-check" [level=6] [ref=e629] - generic [ref=e630]: 7s - button "summarize 6s" [ref=e634] [cursor=pointer]: - generic [ref=e635]: - img [ref=e638] - generic [ref=e642]: - heading "summarize" [level=6] [ref=e643] - generic [ref=e644]: 6s - button "show-sbom 6s" [ref=e648] [cursor=pointer]: - generic [ref=e649]: - img [ref=e652] - generic [ref=e656]: - heading "show-sbom" [level=6] [ref=e657] - generic [ref=e658]: 6s - generic [ref=e662]: - generic [ref=e663]: - button [ref=e664] [cursor=pointer]: - img [ref=e666] - paragraph [ref=e668]: 1/1 - button [ref=e669] [cursor=pointer]: - img [ref=e671] - textbox "Search" [active] [ref=e675]: STEP-SHOW-SBOM - button [ref=e676] [cursor=pointer]: - img [ref=e678] - generic [ref=e681]: - generic [ref=e682]: - row "7955" [ref=e683] [cursor=pointer] - generic [ref=e684]: "{" - generic [ref=e685]: - row "7956" [ref=e686] [cursor=pointer] - generic [ref=e687]: "\"ref\": \"pkg:rpm/redhat/libgcc@11.5.0-11.el9?arch=x86_64&distro=rhel-9.7&package-id=06e2c48d975ea1da&upstream=gcc-11.5.0-11.el9.src.rpm\"," - generic [ref=e688]: - row "7957" [ref=e689] [cursor=pointer] - generic [ref=e690]: "\"dependsOn\": [" - generic [ref=e691]: - row "7958" [ref=e692] [cursor=pointer] - generic [ref=e693]: "\"pkg:rpm/redhat/glibc@2.34-231.el9_7.10?arch=x86_64&distro=rhel-9.7&package-id=6cae8570f9132c10&upstream=glibc-2.34-231.el9_7.10.src.rpm\"" - generic [ref=e694]: - row "7959" [ref=e695] [cursor=pointer] - generic [ref=e696]: "]" - generic [ref=e697]: - row "7960" [ref=e698] [cursor=pointer] - generic [ref=e699]: "}," - generic [ref=e700]: - row "7961" [ref=e701] [cursor=pointer] - generic [ref=e702]: "{" - generic [ref=e703]: - row "7962" [ref=e704] [cursor=pointer] - generic [ref=e705]: "\"ref\": \"pkg:rpm/redhat/libselinux@3.6-3.el9?arch=x86_64&distro=rhel-9.7&package-id=ccc2461d41d72dde&upstream=libselinux-3.6-3.el9.src.rpm\"," - generic [ref=e706]: - row "7963" [ref=e707] [cursor=pointer] - generic [ref=e708]: "\"dependsOn\": [" - generic [ref=e709]: - row "7964" [ref=e710] [cursor=pointer] - generic [ref=e711]: "\"pkg:rpm/redhat/glibc@2.34-231.el9_7.10?arch=x86_64&distro=rhel-9.7&package-id=6cae8570f9132c10&upstream=glibc-2.34-231.el9_7.10.src.rpm\"," - generic [ref=e712]: - row "7965" [ref=e713] [cursor=pointer] - generic [ref=e714]: "\"pkg:rpm/redhat/libsepol@3.6-3.el9?arch=x86_64&distro=rhel-9.7&package-id=cecb06c03b371de6&upstream=libsepol-3.6-3.el9.src.rpm\"," - generic [ref=e715]: - row "7966" [ref=e716] [cursor=pointer] - generic [ref=e717]: "\"pkg:rpm/redhat/pcre2@10.40-6.el9?arch=x86_64&distro=rhel-9.7&package-id=d52857c4436af57f&upstream=pcre2-10.40-6.el9.src.rpm\"" - generic [ref=e718]: - row "7967" [ref=e719] [cursor=pointer] - generic [ref=e720]: "]" - generic [ref=e721]: - row "7968" [ref=e722] [cursor=pointer] - generic [ref=e723]: "}," - generic [ref=e724]: - row "7969" [ref=e725] [cursor=pointer] - generic [ref=e726]: "{" - generic [ref=e727]: - row "7970" [ref=e728] [cursor=pointer] - generic [ref=e729]: "\"ref\": \"pkg:rpm/redhat/libsepol@3.6-3.el9?arch=x86_64&distro=rhel-9.7&package-id=cecb06c03b371de6&upstream=libsepol-3.6-3.el9.src.rpm\"," - generic [ref=e730]: - row "7971" [ref=e731] [cursor=pointer] - generic [ref=e732]: "\"dependsOn\": [" - generic [ref=e733]: - row "7972" [ref=e734] [cursor=pointer] - generic [ref=e735]: "\"pkg:rpm/redhat/glibc@2.34-231.el9_7.10?arch=x86_64&distro=rhel-9.7&package-id=6cae8570f9132c10&upstream=glibc-2.34-231.el9_7.10.src.rpm\"" - generic [ref=e736]: - row "7973" [ref=e737] [cursor=pointer] - generic [ref=e738]: "]" - generic [ref=e739]: - row "7974" [ref=e740] [cursor=pointer] - generic [ref=e741]: "}," - generic [ref=e742]: - row "7975" [ref=e743] [cursor=pointer] - generic [ref=e744]: "{" - generic [ref=e745]: - row "7976" [ref=e746] [cursor=pointer] - generic [ref=e747]: "\"ref\": \"pkg:rpm/redhat/ncurses-libs@6.2-12.20210508.el9?arch=x86_64&distro=rhel-9.7&package-id=9dc1b34cdde2c695&upstream=ncurses-6.2-12.20210508.el9.src.rpm\"," - generic [ref=e748]: - row "7977" [ref=e749] [cursor=pointer] - generic [ref=e750]: "\"dependsOn\": [" - generic [ref=e751]: - row "7978" [ref=e752] [cursor=pointer] - generic [ref=e753]: "\"pkg:rpm/redhat/glibc@2.34-231.el9_7.10?arch=x86_64&distro=rhel-9.7&package-id=6cae8570f9132c10&upstream=glibc-2.34-231.el9_7.10.src.rpm\"," - generic [ref=e754]: - row "7979" [ref=e755] [cursor=pointer] - generic [ref=e756]: "\"pkg:rpm/redhat/ncurses-base@6.2-12.20210508.el9?arch=noarch&distro=rhel-9.7&package-id=cb11b32d6ce6627c&upstream=ncurses-6.2-12.20210508.el9.src.rpm\"" - generic [ref=e757]: - row "7980" [ref=e758] [cursor=pointer] - generic [ref=e759]: "]" - generic [ref=e760]: - row "7981" [ref=e761] [cursor=pointer] - generic [ref=e762]: "}," - generic [ref=e763]: - row "7982" [ref=e764] [cursor=pointer] - generic [ref=e765]: "{" - generic [ref=e766]: - row "7983" [ref=e767] [cursor=pointer] - generic [ref=e768]: "\"ref\": \"pkg:rpm/redhat/pcre2@10.40-6.el9?arch=x86_64&distro=rhel-9.7&package-id=d52857c4436af57f&upstream=pcre2-10.40-6.el9.src.rpm\"," - generic [ref=e769]: - row "7984" [ref=e770] [cursor=pointer] - generic [ref=e771]: "\"dependsOn\": [" - generic [ref=e772]: - row "7985" [ref=e773] [cursor=pointer] - generic [ref=e774]: "\"pkg:rpm/redhat/glibc@2.34-231.el9_7.10?arch=x86_64&distro=rhel-9.7&package-id=6cae8570f9132c10&upstream=glibc-2.34-231.el9_7.10.src.rpm\"," - generic [ref=e775]: - row "7986" [ref=e776] [cursor=pointer] - generic [ref=e777]: "\"pkg:rpm/redhat/pcre2-syntax@10.40-6.el9?arch=noarch&distro=rhel-9.7&package-id=79b3a388130aa9b9&upstream=pcre2-10.40-6.el9.src.rpm\"" - generic [ref=e778]: - row "7987" [ref=e779] [cursor=pointer] - generic [ref=e780]: "]" - generic [ref=e781]: - row "7988" [ref=e782] [cursor=pointer] - generic [ref=e783]: "}," - generic [ref=e784]: - row "7989" [ref=e785] [cursor=pointer] - generic [ref=e786]: "{" - generic [ref=e787]: - row "7990" [ref=e788] [cursor=pointer] - generic [ref=e789]: "\"ref\": \"pkg:rpm/redhat/setup@2.13.7-10.el9?arch=noarch&distro=rhel-9.7&package-id=5e411c4e4f6d3d56&upstream=setup-2.13.7-10.el9.src.rpm\"," - generic [ref=e790]: - row "7991" [ref=e791] [cursor=pointer] - generic [ref=e792]: "\"dependsOn\": [" - generic [ref=e793]: - row "7992" [ref=e794] [cursor=pointer] - generic [ref=e795]: "\"pkg:rpm/redhat/redhat-release@9.7-0.7.el9?arch=x86_64&distro=rhel-9.7&package-id=50aa69013227a9e6&upstream=redhat-release-9.7-0.7.el9.src.rpm\"" - generic [ref=e796]: - row "7993" [ref=e797] [cursor=pointer] - generic [ref=e798]: "]" - generic [ref=e799]: - row "7994" [ref=e800] [cursor=pointer] - generic [ref=e801]: "}" - generic [ref=e802]: - row "7995" [ref=e803] [cursor=pointer] - generic [ref=e804]: "]" - generic [ref=e805]: - row "7996" [ref=e806] [cursor=pointer] - generic [ref=e807]: "}" - generic [ref=e808]: - row "7997" [ref=e809] [cursor=pointer] - generic [ref=e810]: SBOM_EYECATCHER_END - row "7998" [ref=e812] [cursor=pointer] ``` # Test source ```ts 1 | import { expect, Page, Locator } from '@playwright/test'; 2 | import { BaseCIPlugin } from './baseCIPlugin'; 3 | import { TektonPO } from '../../page-objects/tektonPo'; 4 | import { CiPo } from '../../page-objects/ciPo'; 5 | import { CommonPO } from '../../page-objects/commonPo'; 6 | 7 | export class TektonPlugin extends BaseCIPlugin { 8 | constructor(name: string, registryOrg: string) { 9 | super(name, registryOrg); 10 | } 11 | 12 | private async checkActionButtons(onPushRow: Locator): Promise { 13 | for (const testId of [TektonPO.logsIconTestId, TektonPO.sbomIconTestId, TektonPO.viewOutputTestId]) { 14 | const button = onPushRow.getByTestId(testId); 15 | await expect(button).toBeVisible(); 16 | } 17 | } 18 | 19 | private async checkLogsPopup(page: Page, row: Locator): Promise { 20 | const logsButton = row.getByTestId(TektonPO.logsIconTestId); 21 | await logsButton.click(); 22 | 23 | const logsPopup = page.getByTitle(TektonPO.logsDialogTitle); 24 | await expect(logsPopup).toBeVisible(); 25 | 26 | for (const task of TektonPO.sourceTasks) { 27 | const button = page.getByRole('heading', { name: task, exact: true }); 28 | await expect(button).toBeVisible(); 29 | } 30 | 31 | const button = page.getByRole('heading', { name: TektonPO.sourceTasks[0] }); 32 | await button.click(); 33 | 34 | // Check the log is visible by looking for the word 'STEP' 35 | const span = page.getByText(TektonPO.logStepRegex).first(); 36 | await expect(span).toBeVisible(); 37 | 38 | // Close popup 39 | const closeButton = page.getByRole('dialog').getByTestId(CommonPO.closeIconTestId); 40 | await closeButton.click(); 41 | } 42 | 43 | async checkSBOMpopup(page: Page, row: Locator): Promise { 44 | const sbomButton = row.getByTestId(TektonPO.sbomIconTestId); 45 | await sbomButton.click(); 46 | 47 | const searchBox = page.getByRole('textbox', { name: TektonPO.searchBoxName }); 48 | await searchBox.fill(TektonPO.sbomStepName); 49 | 50 | const span = page.getByText(TektonPO.sbomStepName); > 51 | await expect(span).toBeVisible(); | ^ Error: expect(locator).toBeVisible() failed 52 | 53 | // Close popup 54 | const closeButton = page.getByRole('dialog').getByTestId(CommonPO.closeIconTestId); 55 | await closeButton.click(); 56 | } 57 | 58 | private async checkGraph(page: Page, row: Locator): Promise { 59 | const expandButton = row.getByRole('button', { name: TektonPO.expandButtonName }); 60 | const graph = page.locator(TektonPO.graphSelector); 61 | 62 | // Expand the row 63 | await expandButton.click(); 64 | 65 | // Check the graph is visible 66 | await expect(graph).toBeVisible(); 67 | 68 | // Fit to screen 69 | await page.getByRole('button', { name: TektonPO.fitToScreenButtonName }).click(); 70 | 71 | // Check all the tasks are visible 72 | for (const taskName of TektonPO.sourceTasks) { 73 | const task = page.locator(`g[data-test="task ${taskName}"]`); 74 | await expect(task).toBeVisible(); 75 | } 76 | 77 | // Check the graph buttons are visible 78 | for(const buttonName of [TektonPO.zoomInButtonName, TektonPO.zoomOutButtonName, TektonPO.fitToScreenButtonName, TektonPO.resetViewButtonName]) { 79 | const button = page.getByRole('button', { name: buttonName }); 80 | await expect(button).toBeVisible(); 81 | } 82 | 83 | // Collapse the row 84 | await expandButton.click(); 85 | 86 | await expect(graph).not.toBeVisible(); 87 | } 88 | 89 | async checkPipelineRunsTable(page: Page): Promise { 90 | // Wait for the Pipeline Runs section to be visible 91 | await expect(page.getByRole('heading', { name: /pipeline runs/i })).toBeVisible(); 92 | 93 | // Find the table and on-push row 94 | const table = page.locator('table').filter({ has: page.getByRole('columnheader', { name: 'NAME' }) }); 95 | const firstRow = table.locator('tbody tr').filter({ hasText: TektonPO.onPushRowRegex }).first(); 96 | await expect(firstRow).toBeVisible(); 97 | 98 | // 1. Shield icon next to name (look for shield icon with specific path, not the expand arrow) 99 | const shieldIcon = firstRow.locator('.signed-indicator svg'); 100 | await expect(shieldIcon).toBeVisible(); 101 | 102 | // 2. Vulnerabilities are shown (look for vulnerability severity levels) 103 | await expect(firstRow.getByRole('cell').filter({ hasText: TektonPO.vulnerabilitySeverityRegex }).first()).toBeVisible(); 104 | 105 | // 3. Status is Succeeded and has a tick 106 | await expect(firstRow).toContainText(CiPo.statusSucceededText); 107 | await expect(firstRow.locator(`[data-testid="${CiPo.statusOkTestId}"]`)).toBeVisible(); 108 | 109 | // 4. Started column has a date and time format (look for date pattern in any cell) 110 | await expect(firstRow.getByRole('cell').filter({ hasText: /\d{1,2}\/\d{1,2}\/\d{4}/ })).toBeVisible(); 111 | 112 | // 5. Task status has a visible bar (look for progress elements) 113 | // Skipping until https://redhat.atlassian.net/browse/SSCUI-82 is fixed 114 | //await expect(firstRow.locator('[role="progressbar"], [class*="bar"], [data-testid*="progress"]').first()).toBeVisible(); 115 | 116 | // 6. Duration is visible (e.g. `3 minutes 20 seconds`, `3 minutes`, or `45 seconds`) 117 | await expect(firstRow.getByRole('cell').filter({ hasText: TektonPO.durationRegex })).toBeVisible(); 118 | } 119 | 120 | async checkActions(page: Page): Promise { 121 | // Find the Pipeline Runs table specifically to avoid conflicts with other tables (e.g., ArgoCD) 122 | const pipelineRunsTable = page.locator('table').filter({ has: page.getByRole('columnheader', { name: 'NAME' }) }); 123 | 124 | // Scroll to the action column header within the Pipeline Runs table 125 | await pipelineRunsTable.getByRole('columnheader', { name: TektonPO.actionsColumnHeader, exact: true }).scrollIntoViewIfNeeded(); 126 | 127 | const onPushRow = pipelineRunsTable.locator('tr').filter({ hasText: TektonPO.onPushRowRegex }).first(); 128 | 129 | await this.checkActionButtons(onPushRow); 130 | await this.checkLogsPopup(page, onPushRow); 131 | await this.checkSBOMpopup(page, onPushRow); 132 | await this.checkViewOutputPopup(page, onPushRow); 133 | await this.checkGraph(page, onPushRow); 134 | } 135 | 136 | /** 137 | * Verifies that registry links in both Image Scan and Image Check tabs 138 | * are actual clickable links that lead to an external registry (outside Developer Hub). 139 | * 140 | * This method: 141 | * 1. Opens the "View Output" dialog for an on-push pipeline row 142 | * 2. Checks Image Scan tab - verifies the image link is a real link (not just text) 143 | * 3. Checks Image Check tab - verifies the image link is a real link (not just text) 144 | * 4. Confirms links open in new tabs and navigate outside Developer Hub 145 | * 146 | * @param page - Playwright Page object 147 | */ 148 | public async checkImageRegistryLinks(page: Page): Promise { 149 | // Find the Pipeline Runs table (same pattern as checkActions) 150 | const pipelineRunsTable = page.locator('table').filter({ has: page.getByRole('columnheader', { name: 'NAME' }) }); 151 | ```