# 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 30000ms exceeded. ``` ``` Error: expect(locator).toBeVisible() failed Locator: locator('table').filter({ has: getByRole('columnheader', { name: 'ID', exact: true }) }).locator('tbody tr[index]').first().locator('td').nth(3).getByTestId('status-ok') Expected: visible Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 60000ms - waiting for locator('table').filter({ has: getByRole('columnheader', { name: 'ID', exact: true }) }).locator('tbody tr[index]').first().locator('td').nth(3).getByTestId('status-ok') ``` # Page snapshot ```yaml - generic [ref=e3]: - navigation [ref=e5]: - generic [ref=e6]: - link "Home" [ref=e8] [cursor=pointer]: - /url: / - img [ref=e9] - generic [ref=e18]: - img [ref=e20] - combobox "Search..." [ref=e22] - generic "Self-service" [ref=e25]: - link "Self-service" [ref=e26] [cursor=pointer]: - /url: /create - img [ref=e28] - button "Your starred items" [ref=e31] [cursor=pointer]: - img [ref=e32] - button "Application launcher" [ref=e35] [cursor=pointer]: - img [ref=e36] - button "Help" [ref=e39] [cursor=pointer]: - img [ref=e40] - separator [ref=e42] - button "Admin" [ref=e44] [cursor=pointer]: - generic [ref=e45]: - img [ref=e46] - paragraph [ref=e49]: Admin - img [ref=e50] - generic [ref=e53]: - navigation "sidebar nav": - generic [ref=e55]: - generic [ref=e58]: - link "Home" [ref=e60] [cursor=pointer]: - /url: / - img [ref=e64] - generic [ref=e66]: Home - link "Catalog" [ref=e68] [cursor=pointer]: - /url: /catalog - img [ref=e72] - generic [ref=e74]: Catalog - link "APIs" [ref=e76] [cursor=pointer]: - /url: /api-docs - img [ref=e80] - generic [ref=e82]: APIs - link "Learning Paths" [ref=e84] [cursor=pointer]: - /url: /learning-paths - img [ref=e88] - generic [ref=e90]: Learning Paths - separator [ref=e91] - link "Docs" [ref=e94] [cursor=pointer]: - /url: /docs - img [ref=e98] - generic [ref=e100]: Docs - generic [ref=e101]: - separator [ref=e102] - button "Administration" [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 "e2e-tests-dotnet-basic-yzrxrqnw Add to favorites" [level=1] [ref=e119]: - generic [ref=e120]: - generic "component:default/e2e-tests-dotnet-basic-yzrxrqnw | service | Secure Supply Chain Example for C# .Net 6.0 example with advanced continuous integration pipeline covering building, CVE scanning, security scanning, signatures, attestations, SLSA provenance and SBOM along with Gitops-based continuous deployment." [ref=e122]: e2e-tests-dotnet-basic-yzrxrqnw - button "Add to favorites" [ref=e123] [cursor=pointer]: - img [ref=e126] - generic [ref=e128]: - generic [ref=e130]: - paragraph [ref=e131]: Owner - paragraph [ref=e132]: - link "user:guest" [ref=e133] [cursor=pointer]: - /url: /catalog/default/user/guest - generic "user:default/guest" [ref=e134]: - img [ref=e136] - text: user:guest - generic [ref=e139]: - paragraph [ref=e140]: Lifecycle - paragraph [ref=e141]: experimental - button "more" [ref=e142] [cursor=pointer]: - img [ref=e144] - tablist "tabs" [ref=e150]: - tab "Overview" [ref=e151] [cursor=pointer] - tab "Topology" [ref=e152] [cursor=pointer] - tab "CI" [selected] [ref=e153] [cursor=pointer] - tab "CD" [ref=e154] [cursor=pointer] - tab "Kubernetes" [ref=e155] [cursor=pointer] - tab "Image Registry" [ref=e156] [cursor=pointer] - tab "API" [ref=e157] [cursor=pointer] - tab "Dependencies" [ref=e158] [cursor=pointer] - tab "Docs" [ref=e159] [cursor=pointer] - article [ref=e161]: - generic [ref=e162]: - generic [ref=e165]: - generic [ref=e166]: - heading "Azure Pipelines - Builds (2)" [level=2] [ref=e168]: - generic [ref=e169]: - img [ref=e170] - text: Azure Pipelines - Builds (2) - generic [ref=e174]: - img [ref=e176] - textbox "Search" [ref=e178]: - /placeholder: Filter - generic [ref=e179]: - button "Clear Search" [disabled]: - generic: - img - table [ref=e184]: - rowgroup [ref=e185]: - row "ID Build Source State Duration Age Logs" [ref=e186]: - columnheader "ID" [ref=e187]: - button "ID" [ref=e188] [cursor=pointer]: - button "ID" [ref=e189] - img [ref=e190] - columnheader "Build" [ref=e192]: - button "Build" [ref=e193] [cursor=pointer]: - button "Build" [ref=e194] - img [ref=e195] - columnheader "Source" [ref=e197]: - button "Source" [ref=e198] [cursor=pointer]: - button "Source" [ref=e199] - img [ref=e200] - columnheader "State" [ref=e202]: - button "State" [ref=e203] [cursor=pointer]: - button "State" [ref=e204] - img [ref=e205] - columnheader "Duration" [ref=e207]: - button "Duration" [ref=e208] [cursor=pointer]: - button "Duration" [ref=e209] - img [ref=e210] - columnheader "Age" [ref=e212]: - button "Age" [ref=e213] [cursor=pointer]: - button "Age" [ref=e214] - img [ref=e215] - columnheader "Logs" [ref=e217]: - button "Logs" [ref=e218] [cursor=pointer]: - button "Logs" [ref=e219] - img [ref=e220] - rowgroup [ref=e222]: - row "12817 e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 , Opens in a new window refs/heads/main (a3445caf) Canceled 9s 19 minutes ago View Logs" [ref=e223]: - cell "12817" [ref=e224] - cell "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 , Opens in a new window" [ref=e225]: - link "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 , Opens in a new window" [ref=e226] [cursor=pointer]: - /url: https://dev.azure.com/rhtap-test/4c8d8579-6376-4b12-ad25-dedb0e062dca/_build/results?buildId=12817 - text: e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 - generic [ref=e227]: ", Opens in a new window" - cell "refs/heads/main (a3445caf)" [ref=e228] - cell "Canceled" [ref=e229]: - generic [ref=e232]: - img [ref=e234] - text: Canceled - cell "9s" [ref=e236]: - paragraph [ref=e238]: 9s - cell "19 minutes ago" [ref=e239] - cell "View Logs" [ref=e240]: - button "View Logs" [ref=e241] [cursor=pointer]: - generic [ref=e242]: View Logs - row "12819 e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 , Opens in a new window refs/heads/main (653bc10c) Succeeded 3m, 55s 19 minutes ago View Logs" [ref=e243]: - cell "12819" [ref=e244] - cell "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 , Opens in a new window" [ref=e245]: - link "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 , Opens in a new window" [ref=e246] [cursor=pointer]: - /url: https://dev.azure.com/rhtap-test/4c8d8579-6376-4b12-ad25-dedb0e062dca/_build/results?buildId=12819 - text: e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 - generic [ref=e247]: ", Opens in a new window" - cell "refs/heads/main (653bc10c)" [ref=e248] - cell "Succeeded" [ref=e249]: - generic [ref=e252]: - img [ref=e254] - text: Succeeded - cell "3m, 55s" [ref=e256]: - paragraph [ref=e258]: 3m, 55s - cell "19 minutes ago" [ref=e259] - cell "View Logs" [ref=e260]: - button "View Logs" [ref=e261] [cursor=pointer]: - generic [ref=e262]: View Logs - row [ref=e263] - row [ref=e264] - row [ref=e265] - row [ref=e266] - table [ref=e267]: - rowgroup [ref=e268]: - row "5 rows First Page Previous Page 1-2 of 2 Next Page Last Page" [ref=e269]: - cell "5 rows First Page Previous Page 1-2 of 2 Next Page Last Page" [ref=e270]: - generic [ref=e271]: - generic [ref=e272]: - 'button "Rows per page: 5 rows" [ref=e273] [cursor=pointer]': - generic [ref=e274]: 5 rows - textbox: "5" - img - generic [ref=e275]: - generic "First Page" [ref=e276]: - button "First Page" [disabled]: - generic: - img - generic "Previous Page" [ref=e277]: - button "Previous Page" [disabled]: - generic: - img - generic [ref=e278]: 1-2 of 2 - generic "Next Page" [ref=e279]: - button "Next Page" [disabled]: - generic: - img - generic "Last Page" [ref=e280]: - button "Last Page" [disabled]: - generic: - img - generic [ref=e284]: - heading "Security Information" [level=4] [ref=e287] - generic [ref=e289]: - tablist "Multi CI" [ref=e292]: - tab "Azure Pipelines" [selected] [ref=e293] [cursor=pointer]: - generic [ref=e294]: Azure Pipelines - generic [ref=e298]: - generic [ref=e299]: - generic [ref=e302]: - generic [ref=e304]: - img [ref=e306] - button "Name" [ref=e308] [cursor=pointer] - textbox: Name - img - generic "search" [ref=e310]: - img [ref=e312] - textbox "Search by name" [ref=e314] - generic [ref=e316]: - generic "rows per page" [ref=e317]: - button "1 - 2 of 2" [ref=e318] [cursor=pointer] - textbox: "5" - img - button "first page" [disabled]: - generic: - img - button "previous page" [disabled]: - generic: - img - generic "page number" [ref=e319]: - generic [ref=e320]: - textbox [ref=e321]: "1" - group - paragraph [ref=e322]: of 1 - button "next page" [disabled]: - generic: - img - button "last page" [disabled]: - generic: - img - table [ref=e324]: - rowgroup [ref=e325]: - row "Pipeline Run ID Type Critical Important Moderate Low SBOM Actions" [ref=e326]: - columnheader "Pipeline Run ID" [ref=e327] - columnheader "Type" [ref=e328] - columnheader "Critical" [ref=e329] - columnheader "Important" [ref=e330] - columnheader "Moderate" [ref=e331] - columnheader "Low" [ref=e332] - columnheader "SBOM" [ref=e333] - columnheader "Actions" [ref=e334] - rowgroup [ref=e335]: - row "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 Build Critical Important Moderate Low Link to SBOM Logs are not available for this run Scan Results are not available for this run" [ref=e336]: - cell "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1" [ref=e337]: - paragraph [ref=e338]: e2e-tests-dotnet-basic-yzrxrqnw - 20260420.1 - cell "Build" [ref=e339]: - paragraph [ref=e340]: Build - cell "Critical" [ref=e341]: - generic "Critical" [ref=e342]: - paragraph [ref=e343]: N/A - cell "Important" [ref=e344]: - generic "Important" [ref=e345]: - paragraph [ref=e346]: N/A - cell "Moderate" [ref=e347]: - generic "Moderate" [ref=e348]: - paragraph [ref=e349]: N/A - cell "Low" [ref=e350]: - generic "Low" [ref=e351]: - paragraph [ref=e352]: N/A - cell "Link to SBOM" [ref=e353]: - generic "Link to SBOM" [ref=e354]: - button [disabled]: - generic: - img - cell "Logs are not available for this run Scan Results are not available for this run" [ref=e355]: - generic [ref=e356]: - generic "Logs are not available for this run" [ref=e357]: - button [disabled]: - generic: - img - generic "Scan Results are not available for this run" [ref=e358]: - button [disabled]: - generic: - img - row "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 Build Critical Important Moderate Low Link to SBOM View Logs View Scan Results" [ref=e359]: - cell "e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2" [ref=e360]: - paragraph [ref=e361]: e2e-tests-dotnet-basic-yzrxrqnw - 20260420.2 - cell "Build" [ref=e362]: - paragraph [ref=e363]: Build - cell "Critical" [ref=e364]: - generic "Critical" [ref=e365]: - img [ref=e366] - text: "0" - cell "Important" [ref=e368]: - generic "Important" [ref=e369]: - img [ref=e370] - text: "43" - cell "Moderate" [ref=e373]: - generic "Moderate" [ref=e374]: - img [ref=e375] - text: "134" - cell "Low" [ref=e377]: - generic "Low" [ref=e378]: - img [ref=e379] - text: "225" - cell "Link to SBOM" [ref=e382]: - generic "Link to SBOM" [ref=e383]: - button [ref=e384] [cursor=pointer]: - img [ref=e386] - cell "View Logs View Scan Results" [ref=e388]: - generic [ref=e389]: - generic "View Logs" [ref=e390]: - button [ref=e391] [cursor=pointer]: - img [ref=e393] - generic "View Scan Results" [ref=e395]: - button [ref=e396] [cursor=pointer]: - img [ref=e398] ``` # Test source ```ts 1 | import { expect, Locator, Page } from '@playwright/test'; 2 | import { BaseCIPlugin } from './baseCIPlugin'; 3 | import { checkWebsiteStatus } from '../../commonUi'; 4 | import { AzurePO } from '../../page-objects/azurePo'; 5 | import { CiPo } from '../../page-objects/ciPo'; 6 | import { CommonPO } from '../../page-objects/commonPo'; 7 | import { LoggerFactory, Logger } from '../../../logger/logger'; 8 | 9 | export class AzurePlugin extends BaseCIPlugin { 10 | private readonly logger: Logger = LoggerFactory.getLogger('AzurePlugin'); 11 | 12 | constructor(name: string, registryOrg: string) { 13 | super(name, registryOrg); 14 | } 15 | 16 | private getPprTable(page: Page): Locator { 17 | return page.locator('table').filter({ 18 | has: page.getByRole('columnheader', { name: AzurePO.columnHeaders[0], exact: true }) 19 | }); 20 | } 21 | 22 | private async checkColumnHeaders(table: Locator): Promise { 23 | for (const header of AzurePO.columnHeaders) { 24 | await expect(table.getByRole('columnheader', { name: header })).toBeVisible(); 25 | } 26 | } 27 | 28 | private async checkRowCellsVisible(cells: Locator[]): Promise { 29 | expect(cells).toHaveLength(AzurePO.columnHeaders.length); 30 | for (const cell of cells) { 31 | await expect(cell).toBeVisible(); 32 | } 33 | } 34 | 35 | private async checkRowCellContents(page: Page, cells: Locator[]): Promise { 36 | const { cellIndex } = AzurePO; 37 | 38 | await expect(cells[cellIndex.id]).toHaveText(AzurePO.pprNumberRegex); 39 | 40 | const pprLink = cells[cellIndex.build].getByRole('link'); 41 | await expect(pprLink).toBeVisible(); 42 | const pprLinkHref = await pprLink.getAttribute('href'); 43 | expect(pprLinkHref).not.toBeNull(); 44 | await checkWebsiteStatus(page, pprLinkHref!); 45 | 46 | await expect(cells[cellIndex.source]).toHaveText(AzurePO.branchCommitRegex); 47 | > 48 | await expect(cells[cellIndex.state].getByTestId(CiPo.statusOkTestId)).toBeVisible(); | ^ Error: expect(locator).toBeVisible() failed 49 | await expect(cells[cellIndex.state]).toContainText(CiPo.statusSucceededText); 50 | 51 | await expect(cells[cellIndex.duration]).toHaveText(AzurePO.durationRegex); 52 | 53 | await expect(cells[cellIndex.age]).toHaveText(AzurePO.relativeTimeRegex); 54 | 55 | await expect(cells[cellIndex.logs].getByRole('button', { name: AzurePO.viewLogsButtonName })).toBeVisible(); 56 | } 57 | 58 | public async checkCIHeading(page: Page): Promise { 59 | await expect(page.getByRole('heading', { name: AzurePO.pipelinesHeading })).toBeVisible(); 60 | } 61 | 62 | public async checkActions(page: Page): Promise { 63 | const pipelineRunsTable = this.getPprTable(page); 64 | const firstRow = pipelineRunsTable.locator(CommonPO.dataRowSelector).first(); 65 | 66 | const viewLogsButton = firstRow.getByRole('button', { name: AzurePO.viewLogsButtonName }); 67 | await expect(viewLogsButton).toBeVisible(); 68 | await viewLogsButton.click(); 69 | 70 | const logsPopup = page.getByRole('heading', { name: AzurePO.logsPopupHeadingRegex }); 71 | await expect(logsPopup).toBeVisible(); 72 | 73 | const closeButton = page.getByRole('button', { name: AzurePO.closeButtonName }); 74 | await closeButton.click(); 75 | } 76 | 77 | public async checkPipelineRunsTable(page: Page): Promise { 78 | const pipelineRunsTable = this.getPprTable(page); 79 | await expect(pipelineRunsTable).toBeVisible(); 80 | 81 | await this.checkColumnHeaders(pipelineRunsTable); 82 | 83 | const tableRows = pipelineRunsTable.locator(CommonPO.dataRowSelector); 84 | await expect(tableRows.first()).toBeVisible(); 85 | 86 | const tableRowCells = await tableRows.first().locator('td').all(); 87 | await this.checkRowCellsVisible(tableRowCells); 88 | await this.checkRowCellContents(page, tableRowCells); 89 | } 90 | 91 | // eslint-disable-next-line no-unused-vars 92 | public async checkImageRegistryLinks(_page: Page): Promise { 93 | this.logger.info('Skipping checkImageRegistryLinks - not applicable for Azure DevOps CI'); 94 | } 95 | } 96 | ```