Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions run-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,20 @@ for ws in "${E2E_WORKSPACES[@]}"; do
WS_DIR="workspaces/${ws}/e2e-tests"
WS_CONFIG="${WS_DIR}/playwright.config.ts"

# Extract content between "projects: [" and "]," (the project objects)
PROJECTS_BLOCK=$(sed -n '/projects: \[/,/^\s*\],/{ /projects: \[/d; /^\s*\],/d; p; }' "$WS_CONFIG")
# Extract content between "projects: [" and its matching "]".
# Uses awk with bracket-depth tracking so nested arrays (e.g. testMatch: [...])
# don't prematurely terminate the extraction.
PROJECTS_BLOCK=$(awk '
/projects:[[:space:]]*\[/ { inside=1; depth=1; next }
inside {
for (i=1; i<=length($0); i++) {
c = substr($0, i, 1)
if (c == "[") depth++
if (c == "]") { depth--; if (depth == 0) { inside=0; next } }
}
if (inside) print
}
' "$WS_CONFIG")

if [[ -z "$PROJECTS_BLOCK" ]]; then
echo "[WARN] No projects found in $WS_CONFIG, skipping"
Expand Down
2 changes: 2 additions & 0 deletions workspaces/orchestrator/e2e-tests/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
nodeLinker: node-modules
npmRegistryServer: https://registry.npmjs.org
3 changes: 3 additions & 0 deletions workspaces/orchestrator/e2e-tests/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createEslintConfig } from "@red-hat-developer-hub/e2e-test-utils/eslint";

export default createEslintConfig(import.meta.dirname);
39 changes: 39 additions & 0 deletions workspaces/orchestrator/e2e-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "orchestrator-e2e-tests",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=22",
"yarn": ">=3"
},
"packageManager": "yarn@3.8.7",
"description": "E2E tests for Orchestrator plugin",
"scripts": {
"test": "playwright test",
"report": "playwright show-report",
"test:ui": "playwright test --ui",
"test:headed": "playwright test --headed",
"lint:check": "eslint .",
"lint:fix": "eslint . --fix",
"prettier:check": "prettier --check .",
"prettier:fix": "prettier --write .",
"tsc:check": "tsc --noEmit",
"check": "yarn tsc:check && yarn lint:check && yarn prettier:check"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@playwright/test": "1.57.0",
"@types/node": "^24.10.1",
"dotenv": "^16.4.7",
"eslint": "^9.39.2",
"eslint-plugin-check-file": "^3.3.1",
"eslint-plugin-playwright": "^2.4.0",
"prettier": "^3.7.4",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.0"
},
"dependencies": {
"@red-hat-developer-hub/e2e-test-utils": "redhat-developer/rhdh-e2e-test-utils#main"
}
}
16 changes: 16 additions & 0 deletions workspaces/orchestrator/e2e-tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineConfig } from "@red-hat-developer-hub/e2e-test-utils/playwright-config";
import dotenv from "dotenv";

dotenv.config({ path: `${import.meta.dirname}/.env` });
/**
* Orchestrator plugin e2e test configuration.
* Extends the base config from rhdh-e2e-test-utils.
*/
export default defineConfig({
projects: [
{
name: "orchestrator",
testMatch: ["specs/orchestrator.spec.ts"],
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# rhdh app config file
# this file is used to merge with the default values of the rhdh app config

app:
title: RHDH Orchestrator Test Instance
backend:
reading:
allow:
- host: github.com
permission:
enabled: true
rbac:
pluginsWithPermission:
- orchestrator
admin:
users:
- name: user:default/test1
orchestrator:
dataIndexService:
url: ${SONATAFLOW_DATA_INDEX_URL}
catalog:
rules:
- allow: [Template, Component, System, Group, Resource, Location, API, User]
locations:
- type: url
target: https://github.com/testetson22/greeting_54mjks/blob/main/templates/greeting/greeting.yaml
- type: url
target: https://github.com/testetson22/greeting_54mjks/blob/main/templates/greeting/greeting_w_component.yaml
10 changes: 10 additions & 0 deletions workspaces/orchestrator/e2e-tests/tests/config/rhdh-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: rhdh-secrets
type: Opaque
stringData:
SONATAFLOW_DATA_INDEX_URL: $SONATAFLOW_DATA_INDEX_URL
LOKI_BASE_URL: http://localhost:3100
# Required by orchestrator-backend-module-loki at startup; e2e does not deploy Loki.
LOKI_TOKEN: e2e-ci-placeholder
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { test, expect } from "@red-hat-developer-hub/e2e-test-utils/test";
import { cleanupGreetingComponentEntity } from "../support/utils/catalog-helpers.js";
import { ensureDataIndexOrSkip } from "../support/utils/cluster-helpers.js";
import { OrchestratorUiPage } from "../support/pages/orchestrator-po.js";

/**
* RHIDP-11833 through RHIDP-11838: Entity-Workflow Integration Tests
*
* These tests verify the integration between RHDH catalog entities and
* Orchestrator workflows, including:
* - EntityPicker-based entity association
* - orchestrator.io/workflows annotation behavior
* - Workflows tab visibility on entity pages
* - Catalog <-> Workflows breadcrumb navigation
* - Template execution -> workflow run linkage
*
* Templates used (from testetson22/greeting_54mjks on GitHub):
* - greeting.yaml: name=greeting, title="Greeting workflow" - NO orchestrator.io/workflows annotation
* - greeting_w_component.yaml: name=greetingComponent, title="Greeting Test Picker" - HAS annotation
*
* These are scaffolder templates that use the orchestrator:workflow:run action
* to trigger the "greeting" SonataFlow workflow deployed by CI.
*/
export function registerOrchestratorEntityWorkflowTests(): void {
test.describe("Entity-Workflow Integration", () => {
let orchestratorUi: OrchestratorUiPage;

test.beforeEach(async ({ page, loginHelper }, testInfo) => {
orchestratorUi = new OrchestratorUiPage(page);
await loginHelper.loginAsKeycloakUser();
await ensureDataIndexOrSkip(testInfo.project.name, test);
});

test.afterAll(async () => {
await cleanupGreetingComponentEntity();
});

test("RHIDP-11833: Run workflow with existing entity", async ({
uiHelper,
}) => {
await orchestratorUi.launchGreetingTemplateFromSelfService(uiHelper, {
entityName: `test-entity-${Date.now()}`,
selectEnglishIfVisible: true,
});
await expect(
orchestratorUi.workflowLink(/Greeting workflow/i),
).toBeVisible();
await orchestratorUi.expectWorkflowHeading(/Greeting workflow/i);
});

test("RHIDP-11834: Show workflow for annotated template", async ({
uiHelper,
}) => {
await orchestratorUi.openGreetingTemplateFromCatalog(uiHelper);
await orchestratorUi.clickWorkflowsTab();
await expect(
orchestratorUi.workflowLink("Greeting workflow"),
).toBeVisible();
await orchestratorUi.expectWorkflowVisible("Greeting workflow");
});

test("RHIDP-11835: Hide workflow for unannotated template", async ({
uiHelper,
}) => {
await orchestratorUi.openTemplateFromCatalog(
uiHelper,
/Greeting workflow/i,
);
await orchestratorUi.expectWorkflowMissingInEntityTab(
"Greeting workflow",
);
await expect(
orchestratorUi.workflowLink("Greeting workflow"),
).toHaveCount(0);
});

test("RHIDP-11836: Navigate Catalog and Workflows via breadcrumb", async ({
uiHelper,
page,
}) => {
await orchestratorUi.openGreetingTemplateFromCatalog(uiHelper);
await orchestratorUi.clickWorkflowsTab();
await orchestratorUi.openGreetingWorkflowFromEntityTab();
await orchestratorUi.openEntityFromBreadcrumb(
"greetingComponent",
/Greeting Test Picker/i,
);
await expect(page).toHaveURL(
/\/catalog\/default\/template\/greetingcomponent(?:\/workflows)?/i,
);
});

test("RHIDP-11837: Show workflow runs after template run", async ({
uiHelper,
}) => {
await orchestratorUi.launchGreetingTemplateFromSelfService(uiHelper, {
entityName: `test-entity-${Date.now()}`,
selectEnglishIfVisible: true,
});
await orchestratorUi.gotoWorkflows(uiHelper, false);
await expect(
orchestratorUi.workflowLink(/Greeting workflow/i),
).toBeVisible();
await orchestratorUi.expectWorkflowVisible(/Greeting workflow/i);
});

test("RHIDP-11838: Show Workflows tab with dynamic plugin config", async ({
uiHelper,
}) => {
await orchestratorUi.openGreetingTemplateFromCatalog(uiHelper);
await orchestratorUi.clickWorkflowsTab();
await expect(
orchestratorUi.workflowLink("Greeting workflow"),
).toBeVisible();
await orchestratorUi.expectWorkflowVisible("Greeting workflow");
});
});
}
Loading
Loading