From 45f14dd4b746e57f5358b4520372c0e4683a8899 Mon Sep 17 00:00:00 2001 From: wadii Date: Thu, 18 Jun 2026 16:45:22 +0200 Subject: [PATCH 1/4] feat: raised db max connections for private cloude e2e --- .github/workflows/.reusable-docker-e2e-tests.yml | 6 ++++++ .github/workflows/platform-pull-request.yml | 1 + frontend/docker-compose-e2e-tests.yml | 1 + 3 files changed, 8 insertions(+) diff --git a/.github/workflows/.reusable-docker-e2e-tests.yml b/.github/workflows/.reusable-docker-e2e-tests.yml index 247361ecb3f4..b6fd246285fa 100644 --- a/.github/workflows/.reusable-docker-e2e-tests.yml +++ b/.github/workflows/.reusable-docker-e2e-tests.yml @@ -22,6 +22,11 @@ on: description: The concurrent number of browsers to be used on testing required: false default: 16 + pg-max-connections: + type: number + description: Postgres max_connections for the E2E database. Raise above the default of 100 for high-concurrency runs (e.g. private-cloud) to avoid connection exhaustion. + required: false + default: 100 runs-on: type: string description: The runner label to use. Defaults to `depot-ubuntu-latest` @@ -115,6 +120,7 @@ jobs: E2E_IMAGE: ${{ inputs.e2e-image }} E2E_CONCURRENCY: ${{ inputs.concurrency }} E2E_RETRIES: 2 + PG_MAX_CONNECTIONS: ${{ inputs.pg-max-connections }} VISUAL_REGRESSION: ${{ inputs.visual-regression && '1' || '' }} VISUAL_REGRESSION_ARGS: ${{ inputs.visual-regression-update && '--update-snapshots' || '' }} SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} diff --git a/.github/workflows/platform-pull-request.yml b/.github/workflows/platform-pull-request.yml index b51f819f6051..f0efc5a20920 100644 --- a/.github/workflows/platform-pull-request.yml +++ b/.github/workflows/platform-pull-request.yml @@ -171,6 +171,7 @@ jobs: api-image: ${{ needs.docker-build-private-cloud.outputs.image }} args: --grep "@oss|@enterprise" visual-regression: ${{ matrix.runs-on == 'depot-ubuntu-latest-16' }} + pg-max-connections: 200 secrets: GCR_TOKEN: ${{ needs.permissions-check.outputs.can-write == 'true' && secrets.GITHUB_TOKEN || '' }} SLACK_TOKEN: ${{ needs.permissions-check.outputs.can-write == 'true' && secrets.SLACK_TOKEN || '' }} diff --git a/frontend/docker-compose-e2e-tests.yml b/frontend/docker-compose-e2e-tests.yml index 1f881ece6303..6dd4fc2878f5 100644 --- a/frontend/docker-compose-e2e-tests.yml +++ b/frontend/docker-compose-e2e-tests.yml @@ -7,6 +7,7 @@ version: '3' services: db: image: docker.io/library/postgres:15-alpine + command: postgres -c max_connections=${PG_MAX_CONNECTIONS:-100} environment: POSTGRES_PASSWORD: password POSTGRES_DB: flagsmith From b7400319d64171f8126bb325bfb9069a0f05cbde Mon Sep 17 00:00:00 2001 From: wadii Date: Thu, 18 Jun 2026 18:07:04 +0200 Subject: [PATCH 2/4] feat: wait for api response before closing modal in permissions tests --- frontend/e2e/helpers/e2e-helpers.playwright.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/e2e/helpers/e2e-helpers.playwright.ts b/frontend/e2e/helpers/e2e-helpers.playwright.ts index ad74b4f56157..3a33731b3c51 100644 --- a/frontend/e2e/helpers/e2e-helpers.playwright.ts +++ b/frontend/e2e/helpers/e2e-helpers.playwright.ts @@ -898,11 +898,20 @@ export class E2EHelpers { if (entityName) { await this.click(byId(`permissions-${entityName.toLowerCase()}`)); } + // Wait for the permission save (POST/PUT) to commit before closing, so a later read can't race the grant. + const savePromise = this.page.waitForResponse( + (res) => + res.url().includes('/user-permissions/') && + ['POST', 'PUT'].includes(res.request().method()) && + res.ok(), + { timeout: LONG_TIMEOUT }, + ); if (permission === 'ADMIN') { await this.click(byId(`admin-switch-${level}`)); } else { await this.click(byId(`permission-switch-${permission}`)); } + await savePromise; await this.closeModal(); } From cfc68acb90c1b9ab7498b4cf1293d0838ea5f63a Mon Sep 17 00:00:00 2001 From: wadii Date: Thu, 18 Jun 2026 18:44:45 +0200 Subject: [PATCH 3/4] feat: verify nav overflow for project settings placement --- .../e2e/helpers/e2e-helpers.playwright.ts | 24 +++++++++++++++++-- frontend/e2e/helpers/utils.playwright.ts | 1 + .../e2e/tests/project-permission-test.pw.ts | 3 ++- .../web/components/navigation/OverflowNav.tsx | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/frontend/e2e/helpers/e2e-helpers.playwright.ts b/frontend/e2e/helpers/e2e-helpers.playwright.ts index 3a33731b3c51..6b438133d262 100644 --- a/frontend/e2e/helpers/e2e-helpers.playwright.ts +++ b/frontend/e2e/helpers/e2e-helpers.playwright.ts @@ -1,8 +1,8 @@ import { Page, expect } from '@playwright/test'; -import { LONG_TIMEOUT, byId, log, logUsingLastSection, getFlagsmith } from './utils.playwright'; +import { LONG_TIMEOUT, SHORT_TIMEOUT, byId, log, logUsingLastSection, getFlagsmith } from './utils.playwright'; // Re-export for backwards compatibility -export { LONG_TIMEOUT, byId, log, logUsingLastSection, getFlagsmith }; +export { LONG_TIMEOUT, SHORT_TIMEOUT, byId, log, logUsingLastSection, getFlagsmith }; export type MultiVariate = { value: string; weight: number }; @@ -40,6 +40,26 @@ export class E2EHelpers { }); } + // Asserts a navbar link is reachable. A link can either be shown inline, or + // collapsed into the OverflowNav "more" menu when the navbar runs out of + // horizontal space (e.g. when a feature flag adds an extra item). Try inline + // first; if it isn't visible, open the overflow menu and retry. Only fails if + // the link is reachable via neither. + async waitForNavElementVisible(selector: string) { + logUsingLastSection(`Waiting nav element visible (inline or overflow) ${selector}`); + const element = this.page.locator(selector).first(); + try { + await element.waitFor({ state: 'visible', timeout: SHORT_TIMEOUT }); + return; + } catch { + const overflowButton = this.page.locator(byId('overflow-nav-button')).first(); + if (await overflowButton.isVisible()) { + await overflowButton.click(); + } + await element.waitFor({ state: 'visible', timeout: LONG_TIMEOUT }); + } + } + async waitForElementNotClickable(selector: string) { logUsingLastSection(`Waiting element not clickable ${selector}`); const element = this.page.locator(selector).first(); diff --git a/frontend/e2e/helpers/utils.playwright.ts b/frontend/e2e/helpers/utils.playwright.ts index 2322496d4da1..f8818aba7b2a 100644 --- a/frontend/e2e/helpers/utils.playwright.ts +++ b/frontend/e2e/helpers/utils.playwright.ts @@ -4,6 +4,7 @@ import { IFlagsmith } from '@flagsmith/flagsmith/types'; import Project from '../../common/project'; export const LONG_TIMEOUT = 20000; +export const SHORT_TIMEOUT = 5000; export const byId = (id: string) => `[data-test="${id}"]`; diff --git a/frontend/e2e/tests/project-permission-test.pw.ts b/frontend/e2e/tests/project-permission-test.pw.ts index 658158672caf..c59d1836fd8e 100644 --- a/frontend/e2e/tests/project-permission-test.pw.ts +++ b/frontend/e2e/tests/project-permission-test.pw.ts @@ -24,6 +24,7 @@ test.describe('Project Permission Tests', () => { waitForElementNotExist, waitForElementVisible, waitForFeatureSwitch, + waitForNavElementVisible, waitForPageFullyLoaded, } = createHelpers(page); @@ -84,7 +85,7 @@ test.describe('Project Permission Tests', () => { log('User with ADMIN permissions can set project settings') await login(E2E_NON_ADMIN_USER_WITH_PROJECT_PERMISSIONS, PASSWORD) await gotoProject(PROJECT_NAME) - await waitForElementVisible('#project-settings-link') + await waitForNavElementVisible('#project-settings-link') await logout() log('Remove user as project ADMIN') await login(E2E_USER, PASSWORD) diff --git a/frontend/web/components/navigation/OverflowNav.tsx b/frontend/web/components/navigation/OverflowNav.tsx index 18861d8bd8f9..944fb7a6831a 100644 --- a/frontend/web/components/navigation/OverflowNav.tsx +++ b/frontend/web/components/navigation/OverflowNav.tsx @@ -82,6 +82,7 @@ const OverflowNav: FC = ({ style={{ height: buttonWidth, width: buttonWidth }} onClick={() => setOpen(!open)} theme='secondary' + data-test='overflow-nav-button' className='d-flex align-items-center justify-content-center m-0 p-0' > From 5d3d0dcf0fde0668d839bf5967c5e2bea828bcc4 Mon Sep 17 00:00:00 2001 From: wadii Date: Thu, 18 Jun 2026 19:12:35 +0200 Subject: [PATCH 4/4] feat: added leak investigation todo --- .github/workflows/platform-pull-request.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/platform-pull-request.yml b/.github/workflows/platform-pull-request.yml index f0efc5a20920..3ecb29788e8c 100644 --- a/.github/workflows/platform-pull-request.yml +++ b/.github/workflows/platform-pull-request.yml @@ -171,6 +171,7 @@ jobs: api-image: ${{ needs.docker-build-private-cloud.outputs.image }} args: --grep "@oss|@enterprise" visual-regression: ${{ matrix.runs-on == 'depot-ubuntu-latest-16' }} + # TODO: identify whether the E2E leaks connections, leading to the connection bloat pg-max-connections: 200 secrets: GCR_TOKEN: ${{ needs.permissions-check.outputs.can-write == 'true' && secrets.GITHUB_TOKEN || '' }}