diff --git a/e2etests/pages/base-page.ts b/e2etests/pages/base-page.ts index f91bc2f22..14020f888 100644 --- a/e2etests/pages/base-page.ts +++ b/e2etests/pages/base-page.ts @@ -944,7 +944,7 @@ export abstract class BasePage { * @returns {Promise} A promise that resolves when the filter is applied. */ async selectFilterByText(filter: string, filterOption: string): Promise { - const filterLocator = this.filtersBox.getByRole('button', { name: new RegExp(`^${filter}`) }); + const filterLocator = this.filtersBox.getByRole('button', { name: new RegExp(`^${filter}`) }).first(); await this.selectFilter(filterLocator, filterOption); } @@ -995,7 +995,7 @@ export abstract class BasePage { if (!(await filter.isVisible())) await this.showMoreFiltersBtn.click(); await filter.click(); - await this.filterPopover.getByLabel(filterOption).click(); + await this.filterPopover.getByLabel(filterOption).first().click(); await this.filterApplyButton.click(); } } diff --git a/e2etests/pages/resources-page.ts b/e2etests/pages/resources-page.ts index 34f39635e..dcf61255b 100644 --- a/e2etests/pages/resources-page.ts +++ b/e2etests/pages/resources-page.ts @@ -238,7 +238,6 @@ export class ResourcesPage extends BasePage { await this.waitForCanvas(); await this.resetFilters(); await this.waitForPageLoad(); - await this.firstResourceItemInTable.waitFor({ timeout: 15000 }); } /** diff --git a/e2etests/setup/global-teardown.ts b/e2etests/setup/global-teardown.ts index 98bf2032c..10a4f4326 100644 --- a/e2etests/setup/global-teardown.ts +++ b/e2etests/setup/global-teardown.ts @@ -39,8 +39,8 @@ async function globalTeardown() { if (subPoolIds.length > 1) { const marketplaceDevId = await getDatasourceIdByNameViaOpsAPI(restAPIRequest, dataSourceName); debugLog('Orphaned Sub-pools found for Marketplace (Dev), proceeding to disconnect data source, delete sub-pools and reconnect data source to clean them up'); - await disconnectDataSource(restAPIRequest, token, marketplaceDevId); await deleteSubPoolsByName(restAPIRequest, token, dataSourceName); + await disconnectDataSource(restAPIRequest, token, marketplaceDevId); await connectDataSource(restAPIRequest, token, dataSourceName); } diff --git a/e2etests/tests/cloud-accounts-tests.spec.ts b/e2etests/tests/cloud-accounts-tests.spec.ts index 55304dd12..4392efeab 100644 --- a/e2etests/tests/cloud-accounts-tests.spec.ts +++ b/e2etests/tests/cloud-accounts-tests.spec.ts @@ -19,7 +19,7 @@ import { import { getCurrentUTCTimestamp, getTimestampWithVariance } from '../utils/date-range-utils'; test.describe('Cloud Accounts Tests', { tag: ['@ui', '@cloud-accounts'] }, () => { - test.fixme(process.env.CI === '1', 'Tests are unstable in CI environment due to external dependencies and may cause data corruption. Run locally for now.'); + test.fixme(); test.describe.configure({ mode: 'serial' }); test.use({ restoreSession: true }); @@ -177,6 +177,7 @@ test.describe('Cloud Accounts Tests', { tag: ['@ui', '@cloud-accounts'] }, () => }); test.describe('Mocked Cloud Accounts Tests', { tag: ['@ui', '@cloud-accounts'] }, () => { + test.fixme(); //'Skipping due to these tests possibly corrupting data due to orphaned sub-pools when disconnecting accounts' test.describe.configure({ mode: 'serial' }); const apiInterceptions: InterceptionEntry[] = [ @@ -259,7 +260,7 @@ test.describe( { tag: ['@ui', '@cloud-accounts', '@events'] }, () => { test.describe.configure({ mode: 'serial' }); - test.fixme(process.env.CI === '1', 'Tests are unstable in CI environment due to external dependencies and may cause data corruption. Run locally for now.'); + test.fixme(); //'Skipping due to these tests possibly corrupting data due to orphaned sub-pools when disconnecting accounts' test.use({ restoreSession: true }); test('[232954] Verify that disconnecting and creating a cloud account is recorded in the events log', async ({ diff --git a/e2etests/tests/expenses-tests.spec.ts b/e2etests/tests/expenses-tests.spec.ts index 13a904fa8..0a3e937d6 100644 --- a/e2etests/tests/expenses-tests.spec.ts +++ b/e2etests/tests/expenses-tests.spec.ts @@ -338,7 +338,8 @@ test.describe('[MPT-12859] Expenses Page Pool Breakdown Tests', { tag: ['@ui', ' await test.step('Load expenses data', async () => { const [expensesResponse] = await Promise.all([ expensesPage.page.waitForResponse( - resp => resp.url().includes('/pools_expenses/') && resp.url().includes('filter_by=pool') && resp.request().method() === 'GET' + resp => resp.url().includes('/pools_expenses/') && resp.url().includes('filter_by=pool') && resp.request().method() === 'GET', + { timeout: 20000 } ), expensesPage.page.reload(), ]); @@ -463,7 +464,8 @@ test.describe('[MPT-12859] Expenses Page Owner Breakdown Tests', { tag: ['@ui', await test.step('Load expenses data', async () => { const [expensesResponse] = await Promise.all([ expensesPage.page.waitForResponse( - resp => resp.url().includes('/pools_expenses/') && resp.url().includes('filter_by=employee') && resp.request().method() === 'GET' + resp => resp.url().includes('/pools_expenses/') && resp.url().includes('filter_by=employee') && resp.request().method() === 'GET', + { timeout: 20000 } ), expensesPage.page.reload(), ]); diff --git a/e2etests/tests/perspective-tests.spec.ts b/e2etests/tests/perspective-tests.spec.ts index c783e7b84..fac7cfed7 100644 --- a/e2etests/tests/perspective-tests.spec.ts +++ b/e2etests/tests/perspective-tests.spec.ts @@ -15,7 +15,7 @@ test.describe('[MPT-18579] Perspective Tests', { tag: ['@ui', '@resources', '@pe await resourcesPage.navigateToResourcesPageAndResetFilters(); const filter = 'Region'; - const filterOption = 'West Europe'; + const filterOption = 'East US'; const categorizeBy = 'Resource type'; const groupByTag = 'costcenter'; const perspectiveName = `Test Perspective ${new Date().getTime()}`; diff --git a/e2etests/utils/api-requests/interceptor.ts b/e2etests/utils/api-requests/interceptor.ts index 83adbbd6e..759978313 100644 --- a/e2etests/utils/api-requests/interceptor.ts +++ b/e2etests/utils/api-requests/interceptor.ts @@ -30,17 +30,21 @@ export async function interceptRESTRequest(page: Page, pattern: RegExp, mock: } /** - * Intercepts GraphQL requests matching the provided operation name + * Intercepts GraphQL requests matching the provided operation name. + * Matches on the request URL (e.g. `api?op=`) so that each + * operation gets its own route handler, replacing the previous single `/api` + * endpoint that was shared by all operations. */ async function interceptGraphQLRequest( page: Page, - urlPattern: RegExp, operationName: string, mock: any, onIntercepted: () => void, variableMatch?: Record ) { - await page.route(urlPattern, async route => { + const requestUrl = new RegExp(`[?&]op=${operationName}(?:&|$)`); + + await page.route(requestUrl, async route => { const postData = route.request().postData(); if (!postData) return route.fallback(); @@ -50,12 +54,12 @@ async function interceptGraphQLRequest( debugLog(`\n=== GraphQL Request Interceptor ===`); debugLog(`Expected operation: ${operationName}`); debugLog(`Actual operation: ${body.operationName}`); - debugLog(`Expected variableMatch: ${variableMatch}`); + debugLog(`Expected variableMatch: ${JSON.stringify(variableMatch)}`); debugLog(`Actual variables: ${JSON.stringify(body.variables, null, 2)}`); // Only proceed if operation name matches if (body.operationName !== operationName) { - //debugLog(`❌ Operation name mismatch - continuing to next interceptor`); + debugLog(`❌ Operation name mismatch - continuing to next interceptor`); return route.fallback(); } @@ -70,7 +74,6 @@ async function interceptGraphQLRequest( }); if (!allVariablesMatch) { - debugLog(`❌ Variable match failed - continuing to next interceptor`); return route.fallback(); } debugLog(`✅ Variable match succeeded`); @@ -112,13 +115,13 @@ export async function apiInterceptors(page: Page, config: InterceptionEntry[], f debugLog(`\n=== Registering Interceptor ${index + 1} ===`); debugLog(`ID: ${interceptorId}`); debugLog(`GraphQL Operation: ${gql || 'N/A'}`); - debugLog(`Variable Match: ${variableMatch || 'None'}`); - debugLog(`URL Pattern: ${urlRegExp}`); + debugLog(`Variable Match: ${JSON.stringify(variableMatch) || 'None'}`); + debugLog(`URL Pattern: ${gql ? `[?&]op=${gql}` : urlRegExp}`); interceptorHits.set(interceptorId, false); return gql - ? interceptGraphQLRequest(page, urlRegExp, gql, mock, registerHit(interceptorId), variableMatch) + ? interceptGraphQLRequest(page, gql, mock, registerHit(interceptorId), variableMatch) : interceptRESTRequest(page, urlRegExp, mock, registerHit(interceptorId)); });