Add playwright test 50/143550/4
authorFiete Ostkamp <fiete.ostkamp@telekom.de>
Mon, 9 Mar 2026 11:23:16 +0000 (12:23 +0100)
committerLukasz Rajewski <lukasz.rajewski@t-mobile.pl>
Wed, 11 Mar 2026 10:08:16 +0000 (10:08 +0000)
- add everything that is required to run playwright
  against the same stack that is used in the
  pipeline for the existing ui tests
- make some instable ui tests more reliable

Issue-ID: SDC-4800
Change-Id: I938ada1aa98aa961e60e24f6128d7164023a1c9f
Signed-off-by: Fiete Ostkamp <fiete.ostkamp@telekom.de>
.gitignore
asdctool/sdc-cassandra-init/version.sh [new file with mode: 0644]
integration-tests/playwright-tests/README.md [new file with mode: 0644]
integration-tests/playwright-tests/package-lock.json [new file with mode: 0644]
integration-tests/playwright-tests/package.json [new file with mode: 0644]
integration-tests/playwright-tests/playwright.config.ts [new file with mode: 0644]
integration-tests/playwright-tests/tests/sdc-sanity.spec.ts [new file with mode: 0644]
integration-tests/pom.xml
integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionCanvasComponent.java
integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/utilities/NotificationComponent.java
pom.xml

index 18c83d4..8a7712b 100644 (file)
@@ -193,3 +193,5 @@ vagrant-asdc-all-in-one/
 Vagrantfile
 
 *.xls
+node_modules
+node
diff --git a/asdctool/sdc-cassandra-init/version.sh b/asdctool/sdc-cassandra-init/version.sh
new file mode 100644 (file)
index 0000000..d4ec295
--- /dev/null
@@ -0,0 +1 @@
+normal['version']="1.16.0"
diff --git a/integration-tests/playwright-tests/README.md b/integration-tests/playwright-tests/README.md
new file mode 100644 (file)
index 0000000..e3f0af5
--- /dev/null
@@ -0,0 +1,116 @@
+# SDC Playwright E2E Tests
+
+Playwright-based end-to-end tests for the SDC frontend. These tests run against the same
+Docker stack used by the existing Selenium/TestNG integration tests (Cassandra, backend,
+frontend, webseal-simulator, etc.) but use [Playwright](https://playwright.dev/) instead
+of Selenium for browser automation.
+
+## Prerequisites
+
+- Node.js 18+ (Playwright ≥ 1.42 requires it)
+- Docker
+- Ports 8080, 8285, 8443, 9042, 9443 free on the host
+
+## Running locally
+
+The tests need the integration-test Docker stack (Cassandra, backend, frontend,
+simulator). If the stack is already running, skip straight to "Run the tests".
+
+### 1. Build Docker images (one-time)
+
+The Docker images (`onap/sdc-backend-all-plugins`, `onap/sdc-frontend`, etc.)
+must exist locally. Build them from the repository root with **both** the
+`all` and `docker` profiles (`-P all` keeps the default module list active
+when other profiles are specified):
+
+```bash
+mvn clean install -P all,docker -DskipTests
+```
+
+> **Note:** `clean` is required so that the `build-helper-maven-plugin`
+> `parse-version` goal (bound to `pre-clean`) runs and resolves
+> `${parsedVersion.*}` variables used in Docker image tags.
+
+### 2. Start the Docker stack
+
+```bash
+mvn pre-integration-test -P run-integration-tests-playwright \
+    -f integration-tests/pom.xml
+```
+
+`pre-integration-test` starts the containers (Cassandra, backend, frontend,
+simulator, etc.) but does **not** run the tests or tear them down, so the
+stack stays up for iterating locally.
+
+Once healthy, the webseal-simulator is reachable at `http://localhost:8285`.
+
+Stop the containers later with:
+
+```bash
+mvn docker:stop -f integration-tests/pom.xml
+```
+
+### 3. Run the tests
+
+```bash
+cd integration-tests/playwright-tests
+npm install
+npx playwright install chromium
+SDC_BASE_URL=http://localhost:8285 npx playwright test
+```
+
+### Headed mode (see the browser)
+
+```bash
+SDC_BASE_URL=http://localhost:8285 npm run test:headed
+```
+
+### View the HTML report
+
+```bash
+npm run test:report
+```
+
+## Running via Maven (full lifecycle)
+
+A single Maven command handles the entire lifecycle — spin up Docker, install
+Node/npm, install Playwright browsers, run the tests, tear down Docker:
+
+```bash
+mvn verify -P run-integration-tests-playwright \
+    -f integration-tests/pom.xml
+```
+
+> This assumes the Docker images already exist locally (see step 1 above).
+
+Reports are written to:
+
+| Artifact             | Path                                                      |
+| -------------------- | --------------------------------------------------------- |
+| HTML report          | `integration-tests/target/playwright-report/index.html`   |
+| JUnit XML            | `integration-tests/target/playwright-reports/results.xml` |
+| Screenshots & traces | `integration-tests/target/playwright-results/`            |
+
+## CI (Jenkins)
+
+The JJB definition in `ci-management` registers the job
+`sdc-integration-tests-{stream}-playwright-verify-java`, which triggers on every
+Gerrit patch set and archives the report artifacts listed above.
+
+## Writing new tests
+
+Add `.spec.ts` files under `tests/`. The Playwright config (`playwright.config.ts`)
+sets `baseURL` from the `SDC_BASE_URL` environment variable (default
+`http://localhost:8285`), so you can use relative URLs in `page.goto()`.
+
+The webseal-simulator login flow is straightforward:
+
+```ts
+await page.goto("/login");
+await page.locator('input[name="userId"]').fill("<userId>");
+await page.locator('input[name="password"]').fill("123123a");
+await page.locator('input[value="Login"]').click();
+await page.waitForURL("**/sdc1**");
+```
+
+See `tests/sdc-sanity.spec.ts` for a working example.
diff --git a/integration-tests/playwright-tests/package-lock.json b/integration-tests/playwright-tests/package-lock.json
new file mode 100644 (file)
index 0000000..537beed
--- /dev/null
@@ -0,0 +1,78 @@
+{
+  "name": "sdc-playwright-tests",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "sdc-playwright-tests",
+      "version": "1.0.0",
+      "devDependencies": {
+        "@playwright/test": "^1.42.0"
+      }
+    },
+    "node_modules/@playwright/test": {
+      "version": "1.58.2",
+      "resolved": "https://artifactory.devops.telekom.de/artifactory/api/npm/registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
+      "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "playwright": "1.58.2"
+      },
+      "bin": {
+        "playwright": "cli.js"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@playwright/test/node_modules/playwright": {
+      "version": "1.58.2",
+      "resolved": "https://artifactory.devops.telekom.de/artifactory/api/npm/registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
+      "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "playwright-core": "1.58.2"
+      },
+      "bin": {
+        "playwright": "cli.js"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "fsevents": "2.3.2"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://artifactory.devops.telekom.de/artifactory/api/npm/registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/playwright-core": {
+      "version": "1.58.2",
+      "resolved": "https://artifactory.devops.telekom.de/artifactory/api/npm/registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
+      "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "playwright-core": "cli.js"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    }
+  }
+}
diff --git a/integration-tests/playwright-tests/package.json b/integration-tests/playwright-tests/package.json
new file mode 100644 (file)
index 0000000..021826e
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "name": "sdc-playwright-tests",
+  "version": "1.0.0",
+  "description": "Playwright end-to-end tests for SDC",
+  "private": true,
+  "scripts": {
+    "test": "npx playwright test",
+    "test:headed": "npx playwright test --headed",
+    "test:report": "npx playwright show-report"
+  },
+  "devDependencies": {
+    "@playwright/test": "^1.42.0"
+  }
+}
diff --git a/integration-tests/playwright-tests/playwright.config.ts b/integration-tests/playwright-tests/playwright.config.ts
new file mode 100644 (file)
index 0000000..4be91c5
--- /dev/null
@@ -0,0 +1,32 @@
+import { defineConfig } from '@playwright/test';
+
+export default defineConfig({
+  testDir: './tests',
+  timeout: 60_000,
+  expect: {
+    timeout: 10_000,
+  },
+  fullyParallel: false,
+  retries: 1,
+  reporter: [
+    ['list'],
+    ['html', { outputFolder: '../target/playwright-report', open: 'never' }],
+    ['junit', { outputFile: '../target/playwright-reports/results.xml' }],
+  ],
+  use: {
+    baseURL: process.env.SDC_BASE_URL || 'http://localhost:8285',
+    trace: 'on',
+    screenshot: 'only-on-failure',
+    ignoreHTTPSErrors: true,
+  },
+  projects: [
+    {
+      name: 'chromium',
+      use: {
+        browserName: 'chromium',
+        viewport: { width: 1920, height: 1080 },
+      },
+    },
+  ],
+  outputDir: '../target/playwright-results',
+});
diff --git a/integration-tests/playwright-tests/tests/sdc-sanity.spec.ts b/integration-tests/playwright-tests/tests/sdc-sanity.spec.ts
new file mode 100644 (file)
index 0000000..3f57772
--- /dev/null
@@ -0,0 +1,54 @@
+import { test, expect } from '@playwright/test';
+
+/**
+ * SDC Sanity Test - Demonstrates Playwright e2e testing with the integration-test Docker stack.
+ *
+ * This test uses the webseal-simulator (sdc-sim) login page to authenticate,
+ * then verifies that the SDC home page loads successfully.
+ *
+ * When running locally:   SDC_BASE_URL=http://localhost:8285 npx playwright test
+ * When running in CI:     The Maven profile sets the URL automatically.
+ */
+
+const SIM_PASSWORD = '123123a';
+
+test.describe('SDC Sanity', () => {
+
+  test('should login via simulator and reach the SDC home page', async ({ page }) => {
+    // Navigate to the simulator login page
+    await page.goto('/login');
+
+    // Verify the login page rendered
+    await expect(page.locator('h1')).toContainText('Webseal simulator');
+
+    // Fill in credentials for the Designer role
+    await page.locator('input[name="userId"]').fill('cs0008');
+    await page.locator('input[name="password"]').fill(SIM_PASSWORD);
+
+    // Submit the login form
+    await page.locator('input[value="Login"]').click();
+
+    // After login the simulator redirects to /sdc1 which loads the SDC UI.
+    // Wait for the URL to contain /sdc1 (the redirect target).
+    await page.waitForURL('**/sdc1**', { timeout: 30_000 });
+
+    // The SDC UI should render – verify the page title or a known element.
+    // The SDC app sets the document title to "SDC" or similar.
+    await expect(page).toHaveTitle(/SDC|STARTER/i, { timeout: 30_000 });
+
+    // The HOME button in the main menu should be visible
+    await expect(page.locator('[data-tests-id="main-menu-button-home"]')).toBeVisible({ timeout: 30_000 });
+  });
+
+  test('should display user quick-links table on the login page', async ({ page }) => {
+    await page.goto('/login');
+
+    // The simulator renders a table of preconfigured users
+    const table = page.locator('table');
+    await expect(table).toBeVisible();
+
+    // At least one user row should be present
+    const rows = table.locator('tr');
+    await expect(rows).not.toHaveCount(0);
+  });
+});
index 1739b6f..378b1e5 100644 (file)
@@ -1483,5 +1483,93 @@ limitations under the License.
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <!-- Playwright-based UI integration tests.
+                 Reuses the same Docker stack as the Selenium tests but runs
+                 Playwright (Node.js) instead of TestNG + Selenium.
+
+                 Usage:
+                   mvn verify -P run-integration-tests-playwright -f integration-tests/pom.xml
+            -->
+            <id>run-integration-tests-playwright</id>
+            <properties>
+                <skipYamlJsonValidator>true</skipYamlJsonValidator>
+                <checkstyle.skip>true</checkstyle.skip>
+                <surefire.skip.tests>true</surefire.skip.tests>
+                <skipTest>false</skipTest>
+                <it.playwright.baseUrl>http://localhost:8285</it.playwright.baseUrl>
+                <it.playwright.nodeVersion>v18.20.8</it.playwright.nodeVersion>
+                <it.playwright.npmVersion>10.8.2</it.playwright.npmVersion>
+            </properties>
+            <build>
+                <plugins>
+                    <!-- Skip the Java failsafe tests in this profile -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </plugin>
+                    <!-- Install Node, run npm install, install browsers, run tests -->
+                    <plugin>
+                        <groupId>com.github.eirslett</groupId>
+                        <artifactId>frontend-maven-plugin</artifactId>
+                        <version>1.12.0</version>
+                        <configuration>
+                            <installDirectory>${project.basedir}/playwright-tests</installDirectory>
+                            <workingDirectory>${project.basedir}/playwright-tests</workingDirectory>
+                            <npmDownloadRoot>${npm.registry}</npmDownloadRoot>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>pw-install-node-and-npm</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>install-node-and-npm</goal>
+                                </goals>
+                                <configuration>
+                                    <nodeVersion>${it.playwright.nodeVersion}</nodeVersion>
+                                    <npmVersion>${it.playwright.npmVersion}</npmVersion>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>pw-npm-install</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>npm</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>install</arguments>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>pw-install-browsers</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>npx</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>playwright install chromium</arguments>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>pw-run-tests</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>npx</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>playwright test</arguments>
+                                    <environmentVariables>
+                                        <SDC_BASE_URL>${it.playwright.baseUrl}</SDC_BASE_URL>
+                                    </environmentVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 </project>
index e29df15..0e481c5 100644 (file)
@@ -143,41 +143,69 @@ public class CompositionCanvasComponent extends AbstractPageObject {
 
     public ComponentInstance createNodeOnServiceCanvas(final String serviceName, final String serviceVersion, final String resourceName,
                                                        final String resourceVersion) {
-        final Point freePositionInCanvas = getFreePositionInCanvas(20);
-        final Point pointFromCanvasCenter = calculateOffsetFromCenter(freePositionInCanvas);
-        try {
-            final Service service =
-                AtomicOperationUtils.getServiceObjectByNameAndVersion(DESIGNER, serviceName, serviceVersion);
-            final Resource resourceToAdd =
-                AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, resourceName, resourceVersion);
-            final ComponentInstance componentInstance = AtomicOperationUtils
-                .addComponentInstanceToComponentContainer(resourceToAdd, service, DESIGNER, true,
-                    String.valueOf(pointFromCanvasCenter.getX()), String.valueOf(pointFromCanvasCenter.getY()))
-                .left().value();
+        final int maxRetries = 3;
+        Exception lastException = null;
+        for (int attempt = 1; attempt <= maxRetries; attempt++) {
+            final Point freePositionInCanvas = getFreePositionInCanvas(20);
+            final Point pointFromCanvasCenter = calculateOffsetFromCenter(freePositionInCanvas);
+            try {
+                final Service service =
+                    AtomicOperationUtils.getServiceObjectByNameAndVersion(DESIGNER, serviceName, serviceVersion);
+                final Resource resourceToAdd =
+                    AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, resourceName, resourceVersion);
+                final ComponentInstance componentInstance = AtomicOperationUtils
+                    .addComponentInstanceToComponentContainer(resourceToAdd, service, DESIGNER, true,
+                        String.valueOf(pointFromCanvasCenter.getX()), String.valueOf(pointFromCanvasCenter.getY()))
+                    .left().value();
 
-            LOGGER.debug("Created instance {} in the Service {}", componentInstance.getName(), serviceName);
-            return componentInstance;
-        } catch (final Exception e) {
-            throw new CompositionCanvasRuntimeException("Could not create node through the API", e);
+                LOGGER.debug("Created instance {} in the Service {}", componentInstance.getName(), serviceName);
+                return componentInstance;
+            } catch (final Exception e) {
+                lastException = e;
+                LOGGER.warn("Attempt {}/{} to create node on service canvas failed: {}", attempt, maxRetries, e.getMessage());
+                if (attempt < maxRetries) {
+                    try {
+                        Thread.sleep(1000L * attempt);
+                    } catch (final InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                }
+            }
         }
+        throw new CompositionCanvasRuntimeException("Could not create node through the API", lastException);
     }
 
     public ComponentInstance createNodeOnResourceCanvas(final String serviceName, final String serviceVersion, final String resourceName,
                                                         final String resourceVersion) {
-        final Point freePositionInCanvas = getFreePositionInCanvas(20);
-        final Point pointFromCanvasCenter = calculateOffsetFromCenter(freePositionInCanvas);
-        try {
-            final Resource service = AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, serviceName, serviceVersion);
-            final Resource resourceToAdd = AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, resourceName, resourceVersion);
-            final ComponentInstance componentInstance =
-                AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceToAdd, service, DESIGNER, true,
-                    String.valueOf(pointFromCanvasCenter.getX()), String.valueOf(pointFromCanvasCenter.getY())).left().value();
+        final int maxRetries = 3;
+        Exception lastException = null;
+        for (int attempt = 1; attempt <= maxRetries; attempt++) {
+            final Point freePositionInCanvas = getFreePositionInCanvas(20);
+            final Point pointFromCanvasCenter = calculateOffsetFromCenter(freePositionInCanvas);
+            try {
+                final Resource service = AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, serviceName, serviceVersion);
+                final Resource resourceToAdd = AtomicOperationUtils.getResourceObjectByNameAndVersion(DESIGNER, resourceName, resourceVersion);
+                final ComponentInstance componentInstance =
+                    AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceToAdd, service, DESIGNER, true,
+                        String.valueOf(pointFromCanvasCenter.getX()), String.valueOf(pointFromCanvasCenter.getY())).left().value();
 
-            LOGGER.debug("Created instance {} in the Service {}", componentInstance.getName(), serviceName);
-            return componentInstance;
-        } catch (final Exception e) {
-            throw new CompositionCanvasRuntimeException("Could not create node through the API", e);
+                LOGGER.debug("Created instance {} in the Service {}", componentInstance.getName(), serviceName);
+                return componentInstance;
+            } catch (final Exception e) {
+                lastException = e;
+                LOGGER.warn("Attempt {}/{} to create node on resource canvas failed: {}", attempt, maxRetries, e.getMessage());
+                if (attempt < maxRetries) {
+                    try {
+                        Thread.sleep(1000L * attempt);
+                    } catch (final InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                }
+            }
         }
+        throw new CompositionCanvasRuntimeException("Could not create node through the API", lastException);
     }
 
     private Point getFreePositionInCanvas(int maxAttempts) {
index 2ffe658..d09f103 100644 (file)
@@ -24,6 +24,7 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 import org.onap.sdc.frontend.ci.tests.pages.AbstractPageObject;
 import org.openqa.selenium.By;
+import org.openqa.selenium.StaleElementReferenceException;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.slf4j.Logger;
@@ -39,11 +40,26 @@ public class NotificationComponent extends AbstractPageObject {
 
     public void waitForNotification(final NotificationType notificationType, final int timeout) {
         final By messageLocator = getMessageLocator(notificationType);
-        final WebElement webElement = waitForElementVisibility(messageLocator, timeout);
-        webElement.click();
+        waitForElementVisibility(messageLocator, timeout);
+        clickNotification(messageLocator);
         waitForElementInvisibility(messageLocator, 5);
     }
 
+    private void clickNotification(final By messageLocator) {
+        int attempts = 0;
+        while (attempts < 3) {
+            try {
+                final WebElement element = findElement(messageLocator);
+                element.click();
+                return;
+            } catch (final StaleElementReferenceException e) {
+                LOGGER.warn("StaleElementReferenceException on notification click, attempt {}", attempts + 1);
+                attempts++;
+            }
+        }
+        LOGGER.warn("Failed to click notification after {} attempts", attempts);
+    }
+
     private By getMessageLocator(final NotificationType notificationType) {
         return By.xpath(getMessageXpath(notificationType));
     }
diff --git a/pom.xml b/pom.xml
index 1ca33e4..6057125 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -1021,7 +1021,7 @@ Modifications copyright (c) 2018-2019 Nokia
         <module>onboarding</module>
         <module>common-app-logging</module>
         <module>common-app-api</module>
-       <module>common-be-tests-utils</module>
+        <module>common-be-tests-utils</module>
         <module>common-be</module>
         <module>catalog-dao</module>
         <module>catalog-model</module>
@@ -1035,6 +1035,30 @@ Modifications copyright (c) 2018-2019 Nokia
         <module>integration-tests</module>
       </modules>
     </profile>
+    <profile>
+      <id>run-integration-tests-playwright</id>
+      <properties>
+        <skipYamlJsonValidator>true</skipYamlJsonValidator>
+        <checkstyle.skip>true</checkstyle.skip>
+        <surefire.skip.tests>true</surefire.skip.tests>
+      </properties>
+      <modules>
+        <module>onboarding</module>
+        <module>common-app-logging</module>
+        <module>common-app-api</module>
+             <module>common-be-tests-utils</module>
+        <module>common-be</module>
+        <module>catalog-dao</module>
+        <module>catalog-model</module>
+        <module>catalog-be</module>
+        <module>catalog-be-plugins</module>
+        <module>asdctool</module>
+        <module>catalog-ui</module>
+        <module>catalog-fe</module>
+        <module>utils/webseal-simulator</module>
+        <module>integration-tests</module>
+      </modules>
+    </profile>
   </profiles>
 
   <repositories>