# 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-fgxhnciu - 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-fgxhnciu-gitops-on-pull-request-bfcdn - 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]: 4/24/2026, 3:33:44 AM - cell [ref=e264]: 45 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-fgxhnciu-gitops-on-pull-request-bjffb - 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]: 4/24/2026, 3:32:07 AM - cell [ref=e324]: 48 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-fgxhnciu-on-push-n2rp8 - 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]: "2" - generic [ref=e386]: - img [ref=e389] - generic [ref=e391]: "2" - generic [ref=e392]: - img [ref=e395] - generic [ref=e398]: "13" - cell [ref=e399]: - paragraph [ref=e400]: - img [ref=e403] - generic [ref=e405]: Succeeded - cell [ref=e406] - cell [ref=e407]: - time [ref=e409]: 4/24/2026, 3:29:24 AM - cell [ref=e410]: 1 minute 48 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-fgxhnciu-on-pull-request-8nckb - 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]: "2" - generic [ref=e472]: - img [ref=e475] - generic [ref=e477]: "2" - generic [ref=e478]: - img [ref=e481] - generic [ref=e484]: "13" - cell [ref=e485]: - paragraph [ref=e486]: - img [ref=e489] - generic [ref=e491]: Succeeded - cell [ref=e492] - cell [ref=e493]: - time [ref=e495]: 4/24/2026, 3:27:16 AM - cell [ref=e496]: 1 minute 51 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]: - button [ref=e527] [cursor=pointer]: - img [ref=e529] - cell [ref=e531]: - generic [ref=e533]: - generic [ref=e535]: PLR - generic [ref=e536]: e2e-tests-go-fgxhnciu-on-push-2bkbk - img [ref=e540] - cell [ref=e543]: - generic [ref=e544]: - generic [ref=e545]: - img [ref=e548] - generic [ref=e550]: "0" - generic [ref=e551]: - img [ref=e554] - generic [ref=e557]: "2" - generic [ref=e558]: - img [ref=e561] - generic [ref=e563]: "2" - generic [ref=e564]: - img [ref=e567] - generic [ref=e570]: "13" - cell [ref=e571]: - paragraph [ref=e572]: - img [ref=e575] - generic [ref=e577]: Succeeded - cell [ref=e578] - cell [ref=e579]: - time [ref=e581]: 4/24/2026, 3:26:30 AM - cell [ref=e582]: 2 minutes 3 seconds - cell [ref=e583]: - generic [ref=e584]: - button [ref=e587] [cursor=pointer]: - img [ref=e589] - button [ref=e593] [cursor=pointer]: - img [ref=e595] - button [ref=e599] [cursor=pointer]: - img [ref=e601] - button [ref=e605] [cursor=pointer]: - img [ref=e607] - row [ref=e609]: - cell [ref=e610] - row [ref=e611]: - cell [ref=e612]: - generic [ref=e613]: - generic [ref=e614]: - button [ref=e615] [cursor=pointer]: 5 rows - textbox: "5" - img - paragraph [ref=e616]: 1-5 of 5 - generic [ref=e617]: - button [disabled]: - generic: - img - button [disabled]: - generic: - img - dialog [ref=e620]: - generic "PipelineRun Logs" [ref=e621]: - heading "PLR e2e-tests-go-fgxhnciu-on-push-n2rp8 close" [level=2] [ref=e622]: - generic [ref=e623]: - generic [ref=e624]: - generic [ref=e626]: PLR - generic [ref=e627]: e2e-tests-go-fgxhnciu-on-push-n2rp8 - button "close" [ref=e628] [cursor=pointer]: - img [ref=e630] - generic [ref=e632]: - generic [ref=e633]: - button "Download" [ref=e635] [cursor=pointer]: - generic [ref=e636]: - img [ref=e637] - text: Download - button "Download all tasks logs" [ref=e640] [cursor=pointer]: - generic [ref=e641]: - img [ref=e642] - text: Download all tasks logs - generic [ref=e644]: - generic [ref=e648]: - button "clone-repository 9s" [ref=e650] [cursor=pointer]: - generic [ref=e651]: - img [ref=e654] - generic [ref=e658]: - heading "clone-repository" [level=6] [ref=e659] - generic [ref=e660]: 9s - button "build 1m 17s" [ref=e664] [cursor=pointer]: - generic [ref=e665]: - img [ref=e668] - generic [ref=e672]: - heading "build" [level=6] [ref=e673] - generic [ref=e674]: 1m 17s - button "deploy 7s" [ref=e678] [cursor=pointer]: - generic [ref=e679]: - img [ref=e682] - generic [ref=e686]: - heading "deploy" [level=6] [ref=e687] - generic [ref=e688]: 7s - button "scan 13s" [ref=e692] [cursor=pointer]: - generic [ref=e693]: - img [ref=e696] - generic [ref=e700]: - heading "scan" [level=6] [ref=e701] - generic [ref=e702]: 13s - button "deployment-check 8s" [ref=e706] [cursor=pointer]: - generic [ref=e707]: - img [ref=e710] - generic [ref=e714]: - heading "deployment-check" [level=6] [ref=e715] - generic [ref=e716]: 8s - button "show-sbom 6s" [ref=e720] [cursor=pointer]: - generic [ref=e721]: - img [ref=e724] - generic [ref=e728]: - heading "show-sbom" [level=6] [ref=e729] - generic [ref=e730]: 6s - button "summarize 7s" [ref=e734] [cursor=pointer]: - generic [ref=e735]: - img [ref=e738] - generic [ref=e742]: - heading "summarize" [level=6] [ref=e743] - generic [ref=e744]: 7s - generic [ref=e748]: - generic [ref=e749]: - button [ref=e750] [cursor=pointer]: - img [ref=e752] - paragraph [ref=e754]: 1/1 - button [ref=e755] [cursor=pointer]: - img [ref=e757] - textbox "Search" [active] [ref=e761]: STEP-SHOW-SBOM - button [ref=e762] [cursor=pointer]: - img [ref=e764] - generic [ref=e767]: - generic [ref=e768]: - row "7955" [ref=e769] [cursor=pointer] - generic [ref=e770]: "{" - generic [ref=e771]: - row "7956" [ref=e772] [cursor=pointer] - generic [ref=e773]: "\"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=e774]: - row "7957" [ref=e775] [cursor=pointer] - generic [ref=e776]: "\"dependsOn\": [" - generic [ref=e777]: - row "7958" [ref=e778] [cursor=pointer] - generic [ref=e779]: "\"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=e780]: - row "7959" [ref=e781] [cursor=pointer] - generic [ref=e782]: "]" - generic [ref=e783]: - row "7960" [ref=e784] [cursor=pointer] - generic [ref=e785]: "}," - generic [ref=e786]: - row "7961" [ref=e787] [cursor=pointer] - generic [ref=e788]: "{" - generic [ref=e789]: - row "7962" [ref=e790] [cursor=pointer] - generic [ref=e791]: "\"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=e792]: - row "7963" [ref=e793] [cursor=pointer] - generic [ref=e794]: "\"dependsOn\": [" - generic [ref=e795]: - row "7964" [ref=e796] [cursor=pointer] - generic [ref=e797]: "\"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=e798]: - row "7965" [ref=e799] [cursor=pointer] - generic [ref=e800]: "\"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=e801]: - row "7966" [ref=e802] [cursor=pointer] - generic [ref=e803]: "\"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=e804]: - row "7967" [ref=e805] [cursor=pointer] - generic [ref=e806]: "]" - generic [ref=e807]: - row "7968" [ref=e808] [cursor=pointer] - generic [ref=e809]: "}," - generic [ref=e810]: - row "7969" [ref=e811] [cursor=pointer] - generic [ref=e812]: "{" - generic [ref=e813]: - row "7970" [ref=e814] [cursor=pointer] - generic [ref=e815]: "\"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=e816]: - row "7971" [ref=e817] [cursor=pointer] - generic [ref=e818]: "\"dependsOn\": [" - generic [ref=e819]: - row "7972" [ref=e820] [cursor=pointer] - generic [ref=e821]: "\"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=e822]: - row "7973" [ref=e823] [cursor=pointer] - generic [ref=e824]: "]" - generic [ref=e825]: - row "7974" [ref=e826] [cursor=pointer] - generic [ref=e827]: "}," - generic [ref=e828]: - row "7975" [ref=e829] [cursor=pointer] - generic [ref=e830]: "{" - generic [ref=e831]: - row "7976" [ref=e832] [cursor=pointer] - generic [ref=e833]: "\"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=e834]: - row "7977" [ref=e835] [cursor=pointer] - generic [ref=e836]: "\"dependsOn\": [" - generic [ref=e837]: - row "7978" [ref=e838] [cursor=pointer] - generic [ref=e839]: "\"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=e840]: - row "7979" [ref=e841] [cursor=pointer] - generic [ref=e842]: "\"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=e843]: - row "7980" [ref=e844] [cursor=pointer] - generic [ref=e845]: "]" - generic [ref=e846]: - row "7981" [ref=e847] [cursor=pointer] - generic [ref=e848]: "}," - generic [ref=e849]: - row "7982" [ref=e850] [cursor=pointer] - generic [ref=e851]: "{" - generic [ref=e852]: - row "7983" [ref=e853] [cursor=pointer] - generic [ref=e854]: "\"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=e855]: - row "7984" [ref=e856] [cursor=pointer] - generic [ref=e857]: "\"dependsOn\": [" - generic [ref=e858]: - row "7985" [ref=e859] [cursor=pointer] - generic [ref=e860]: "\"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=e861]: - row "7986" [ref=e862] [cursor=pointer] - generic [ref=e863]: "\"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=e864]: - row "7987" [ref=e865] [cursor=pointer] - generic [ref=e866]: "]" - generic [ref=e867]: - row "7988" [ref=e868] [cursor=pointer] - generic [ref=e869]: "}," - generic [ref=e870]: - row "7989" [ref=e871] [cursor=pointer] - generic [ref=e872]: "{" - generic [ref=e873]: - row "7990" [ref=e874] [cursor=pointer] - generic [ref=e875]: "\"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=e876]: - row "7991" [ref=e877] [cursor=pointer] - generic [ref=e878]: "\"dependsOn\": [" - generic [ref=e879]: - row "7992" [ref=e880] [cursor=pointer] - generic [ref=e881]: "\"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=e882]: - row "7993" [ref=e883] [cursor=pointer] - generic [ref=e884]: "]" - generic [ref=e885]: - row "7994" [ref=e886] [cursor=pointer] - generic [ref=e887]: "}" - generic [ref=e888]: - row "7995" [ref=e889] [cursor=pointer] - generic [ref=e890]: "]" - generic [ref=e891]: - row "7996" [ref=e892] [cursor=pointer] - generic [ref=e893]: "}" - generic [ref=e894]: - row "7997" [ref=e895] [cursor=pointer] - generic [ref=e896]: SBOM_EYECATCHER_END - row "7998" [ref=e898] [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 | ```