diff --git a/docs/nfs-e2e-triage.md b/docs/nfs-e2e-triage.md index 8cf06739b3..636192f50c 100644 --- a/docs/nfs-e2e-triage.md +++ b/docs/nfs-e2e-triage.md @@ -31,10 +31,10 @@ is the Kubernetes namespace, and a name ending in `-app-next` is what switches | | Count | |---|---| | Workspaces with `e2e-tests/` | 24 | -| **Playwright projects** (= namespaces = cluster claims) | **46** | -| — with an `-app-next` lane today | 6 | +| **Playwright projects** (= namespaces = cluster claims) | **47** | +| — with an `-app-next` lane today | 7 | | — of those, skipped in nightly | 2 (`tech-radar`, `app-defaults`) | -| Legacy-only projects with no NFS lane yet | 40 | +| Legacy-only projects with no NFS lane yet | 39 | | Spec files / static `test()` declarations | 42 / 246 | | Workspaces using the per-workspace `value_file-app-next.yaml` hook | 0 | @@ -132,7 +132,7 @@ lane means anything. | `quay` | 1 | 3 | — | guest | **svc** | real quay.io repo + security scan | oci | 0 | ready | | `github` | 2 | 2 | — | github | **svc** | real GitHub Actions runs + issues | baked-in | 0 | ready (5 pkgs) | | `roadie-backstage-plugins` | 2 | 6 | — | github, guest | **svc** | real GitHub PR data; outbound HTTP | oci | 0 | **all 6 no NFS entry point** (3 do expose `alpha`) | -| `bulk-import` | 2 | 9 | — | github | **svc** | real GitHub repos + generated PRs | baked-in | 17 | ready | +| `bulk-import` | 3 | 9 | ✅ | github | **svc** | real GitHub repos + generated PRs | baked-in | 17 | ready | | `quickstart` | 1 | 2 | — | keycloak | **ctr** | Keycloak (test 1 is guest-only) | oci | 0 | ready | | `global-header` | 2 | 10 | — | keycloak | **ctr** | Keycloak | mixed | 22 | ready | | `extensions` | 1 | 11 | — | keycloak | **ctr** | Keycloak + the catalog index image | baked-in | 6 | **no OCI artifact**; the readiness report infers `nfs-ready` from upstream source since #3284 | @@ -156,11 +156,11 @@ lane means anything. | Class | Projects | Meaning | |---|---|---| | `none` | 3 | needs nothing but the app | -| `svc` | 9 + 8 of `backstage` | needs the internet, not a cluster | +| `svc` | 10 + 8 of `backstage` | needs the internet, not a cluster | | `ctr` | 13 + 2 of `backstage` | needs a container, not a cluster | | `ocp` | 8 + 2 of `backstage` | OpenShift is the subject; stays on Prow | -**About 29 of the 46 projects do not need OpenShift.** Three need no external dependency at +**About 30 of the 47 projects do not need OpenShift.** Three need no external dependency at all. That is the ceiling on what a cluster-free lane could ever cover — not a plan, a bound. --- @@ -240,7 +240,7 @@ So assert a positive DOM fact, not the absence of errors. ## 6. Reproducing the numbers ```bash -# Playwright projects (46) and the app-next lanes among them (6) +# Playwright projects (47) and the app-next lanes among them (7) grep -h 'name: "' workspaces/*/e2e-tests/playwright.config.ts | wc -l grep -h 'name: ".*-app-next"' workspaces/*/e2e-tests/playwright.config.ts diff --git a/workspaces/bulk-import/e2e-tests/playwright.config.ts b/workspaces/bulk-import/e2e-tests/playwright.config.ts index 322b137386..3623702ddc 100644 --- a/workspaces/bulk-import/e2e-tests/playwright.config.ts +++ b/workspaces/bulk-import/e2e-tests/playwright.config.ts @@ -3,6 +3,15 @@ import { defineConfig } from "@red-hat-developer-hub/e2e-test-utils/playwright-c /** * Bulk import plugin e2e test configuration. * Extends the base config from rhdh-e2e-test-utils. + * + * Projects: + * - bulk-import — legacy app shell (default RHIDP merge layers). + * - bulk-import-app-next — namespace ends with -app-next, so e2e-test-utils merges + * NFS (app-next) secrets and default app-auth / app-integrations automatically. + * Runs the same spec as the legacy lane; the rationale for why its locators need + * no branching is next to BULK_IMPORT_HEADING in support/constants. + * - bulk-import-orchestrator — legacy shell, orchestrator-mode config. Deliberately + * has no app-next counterpart: it also needs the orchestrator operator. */ export default defineConfig({ projects: [ @@ -11,6 +20,11 @@ export default defineConfig({ testMatch: "bulk-import.spec.ts", timeout: 30 * 60 * 1000, }, + { + name: "bulk-import-app-next", + testMatch: "bulk-import.spec.ts", + timeout: 30 * 60 * 1000, + }, { name: "bulk-import-orchestrator", testMatch: "bulk-import-orchestrator.spec.ts", diff --git a/workspaces/bulk-import/e2e-tests/support/constants/bulk-import-selectors.ts b/workspaces/bulk-import/e2e-tests/support/constants/bulk-import-selectors.ts index 8f082a0362..a10a1c3f3c 100644 --- a/workspaces/bulk-import/e2e-tests/support/constants/bulk-import-selectors.ts +++ b/workspaces/bulk-import/e2e-tests/support/constants/bulk-import-selectors.ts @@ -6,6 +6,13 @@ export const WAIT_OBJECTS = { export const BULK_IMPORT_ACCORDION_LABEL = "Import to Red Hat Developer Hub" as const; +/** + * Holds for both the legacy and the app-next lanes, from different sources: + * the nav item comes from the plugin's `PageBlueprint` (`title: 'Bulk import'`) under + * NFS and from the Scalprum `menuItem.text` under the legacy shell, while the H1 comes + * from the plugin's own `
` in both — the blueprint sets + * `noHeader: true`, so the shell header is suppressed. + */ export const BULK_IMPORT_HEADING = "Bulk import" as const; export const BULK_IMPORT_ROUTE = "/bulk-import" as const; diff --git a/workspaces/bulk-import/e2e-tests/support/constants/catalog.ts b/workspaces/bulk-import/e2e-tests/support/constants/catalog.ts index 2a6f842ca2..e998b4a2a3 100644 --- a/workspaces/bulk-import/e2e-tests/support/constants/catalog.ts +++ b/workspaces/bulk-import/e2e-tests/support/constants/catalog.ts @@ -1,3 +1,12 @@ +/** + * The catalog-import page, reached directly rather than through the app shell. + * The legacy RHDH shell exposes it behind the global header's "Self-service" button; + * app-next ships no global header, so that path does not exist there. The route is the + * same in both, and this test's subject is what happens after the import, not how the + * page was reached. + */ +export const CATALOG_IMPORT_ROUTE = "/catalog-import" as const; + /** Pre-seeded catalog-import fixture org (not janus-qe PR targets). */ export const CATALOG_FIXTURE_ORG = "janus-test" as const; diff --git a/workspaces/bulk-import/e2e-tests/tests/specs/bulk-import.spec.ts b/workspaces/bulk-import/e2e-tests/tests/specs/bulk-import.spec.ts index fded6d69ed..9a22436381 100644 --- a/workspaces/bulk-import/e2e-tests/tests/specs/bulk-import.spec.ts +++ b/workspaces/bulk-import/e2e-tests/tests/specs/bulk-import.spec.ts @@ -5,6 +5,7 @@ import { GITHUB_ORG, } from "../../support/constants/github"; import { + CATALOG_IMPORT_ROUTE, CATALOG_FIXTURE_REPOS, catalogImportComponentUrl, } from "../../support/constants/catalog"; @@ -24,7 +25,7 @@ import { } from "../../support/constants/bulk-import-selectors"; test.describe("Bulk Import plugin", () => { - const catalogRepoName = `${GITHUB_ORG}-1-bulk-import-test-${Date.now()}`; + const catalogRepoName = `${GITHUB_ORG}-1-bulk-import-test-${Date.now()}-${process.pid}`; const catalogRepoDetails = { name: catalogRepoName, url: `github.com/${GITHUB_ORG}/${catalogRepoName}`, @@ -43,7 +44,7 @@ spec: lifecycle: unknown owner: user:default/${GITHUB_CATALOG_OWNER}`; - const newRepoName = `bulk-import-${Date.now()}`; + const newRepoName = `bulk-import-${Date.now()}-${process.pid}`; const newRepoDetails = { owner: `${GITHUB_ORG}`, repoName: newRepoName, @@ -53,13 +54,42 @@ spec: }; test.beforeAll(async ({ rhdh }) => { - await test.runOnce("bulk-import-rhdh-setup", async () => { - await setupBulkImportRhdh(rhdh, { - appConfig: "tests/config/app-config-rhdh.yaml", - dynamicPlugins: "tests/config/dynamic-plugins.yaml", - valueFile: "tests/config/values.yaml", - }); - }); + const namespace = rhdh.deploymentConfig.namespace; + const isAppNext = namespace.endsWith("-app-next"); + + // NOTE: nightly deliberately exercises a different artifact here, and that is not a + // reason to skip. Because this package is in default.packages.yaml, nightly's DPDY + // resolution rewrites it to `oci://registry.access.redhat.com/rhdh/...:{{inherit}}`, + // so the lane tests the *productized* plugin rather than the ghcr artifact this repo + // pins. For an NFS lane that is the more useful signal, not a weaker one. + // `topology` is in the same position -- frontend package in the DPDY set, app-next + // lane, no nightly skip. The two workspaces that do skip nightly have unrelated and + // verified causes: app-defaults' packages are not in the image at all (RHIDP-15482), + // and tech-radar is shadowed by a baked-in wrapper. Neither applies here. + + // Scope the key by namespace, mirroring what deploy() does internally + // (`deploy-${namespace}`). runOnce keys a flag file by the string alone, in a + // directory shared by every project in the run, so a literal key would let the + // first project's setup satisfy the second one and the app-next lane would never + // deploy into its own namespace. + await test.runOnce( + `bulk-import-rhdh-setup-${rhdh.deploymentConfig.namespace}`, + async () => { + await setupBulkImportRhdh(rhdh, { + appConfig: "tests/config/app-config-rhdh.yaml", + dynamicPlugins: "tests/config/dynamic-plugins.yaml", + valueFile: "tests/config/values.yaml", + }); + }, + ); + + // Without this, a lane that silently failed to enable NFS would just re-run the + // legacy suite and stay green — a false pass on the only thing this lane adds. + // Only the forward direction is asserted: USE_NEW_FRONTEND_SYSTEM=true can legally + // turn NFS on for every lane, so the legacy lane is not constrained here. + if (isAppNext) { + expect(rhdh.deploymentConfig.useNewFrontendSystem).toBe(true); + } await APIHelper.createGitHubRepoWithFile( catalogRepoDetails.owner, @@ -231,8 +261,7 @@ spec: const bulkImport = new BulkImportPO(page, uiHelper, loginHelper); await uiHelper.openSidebar("Catalog"); - await uiHelper.clickButton("Self-service"); - await uiHelper.clickButton("Import an existing Git repository"); + await page.goto(CATALOG_IMPORT_ROUTE); await catalogImport.registerFromComponentUrl(catalogImportedRepo.url); await expect(async () => {