This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 370bc71cf5 feat(#3298): add cypress e2e tests for compact adapter 
feature (#3308)
370bc71cf5 is described below

commit 370bc71cf5757a0e5d83d6c96027a25fa966dbbd
Author: Philipp Zehnder <[email protected]>
AuthorDate: Thu Oct 31 20:12:54 2024 +0100

    feat(#3298): add cypress e2e tests for compact adapter feature (#3308)
    
    * feat(#3298): Add test to validate code editor for compact adapters in UI 
(#3299)
    
    * feat(#3298): Add test to validate code editor for compact adapters in UI
    
    * feat(#3298): Add test to validate success path of add compact adapters 
(#3301)
    
    * feat(#3298): Add test to validate success path of add compact adapters
    
    * feat(#3298): Add header to yml file
    
    * feat(#3298): Return Conflict Status Code for Duplicate Adapter ID (#3302)
    
    * feat(#3298): Return status code conflict when adapter id is already taken
    
    * feat(#3298): Fix checkstyle
    
    * feat(#3298): Add test to check rename rule for compact adapters
    
    * feat(#3298): Add test to check rename unit transformation rule for 
compact adapters
    
    * feat(#3298): Fix e2e tests and improve error message in ui
---
 .../management/AdapterMasterManagement.java        | 58 ++++++++-----
 .../management/AdapterMasterManagementTest.java    | 34 ++++----
 .../streampipes/model/message/Notifications.java   |  6 +-
 .../management/AdapterResourceManager.java         | 29 +++++--
 .../management/AdapterResourceManagerTest.java     | 40 ++++++++-
 .../rest/impl/connect/AdapterResource.java         |  3 +-
 .../rest/impl/connect/CompactAdapterResource.java  | 28 ++++--
 .../connect/compact/machineDataSimulator.yml       | 24 ++++++
 .../support/builder/CompactAdapterBuilder.ts       | 93 ++++++++++++++++++++
 ui/cypress/support/utils/CompactUtils.ts           | 27 ++++++
 ui/cypress/support/utils/GeneralUtils.ts           | 23 +++++
 .../support/utils/ProcessingElementTestUtils.ts    |  2 +-
 .../support/utils/ThirdPartyIntegrationUtils.ts    |  2 +-
 .../support/utils/connect/CompactAdapterUtils.ts   | 81 ++++++++++++++++++
 ui/cypress/support/utils/connect/ConnectBtns.ts    | 10 ++-
 ui/cypress/support/utils/connect/ConnectUtils.ts   | 55 ++++++++++--
 ui/cypress/support/utils/pipeline/PipelineBtns.ts  | 23 +++++
 .../support/utils/{ => pipeline}/PipelineUtils.ts  | 48 +++++------
 .../connect/compact/addCompactAdapter.spec.ts      | 99 ++++++++++++++++++++++
 .../compactAdapterWithTransformation.spec.ts       | 73 ++++++++++++++++
 .../tests/connect/compact/uiConfiguration.spec.ts  | 55 ++++++++++++
 .../deleteAdapterWithMultipleUsers.smoke.spec.ts   |  2 +-
 ui/cypress/tests/connect/editAdapter.smoke.spec.ts |  2 +
 .../connect/editAdapterSettingsAndPipeline.spec.ts |  2 +-
 .../tests/connect/persistInDataLake.smoke.spec.ts  |  2 +-
 .../tests/datalake/configuration.smoke.spec.ts     |  2 +-
 .../restartStreamPipes/restartStreamPipes1.ts      |  2 +-
 .../testJvmArchetype/testJvmArchetype.ts           |  2 +-
 .../tests/pipeline/pipelineTest.smoke.spec.ts      |  2 +-
 .../pipeline/updatePipelineTest.smoke.spec.ts      |  2 +-
 .../PipelineElementDocumentation.spec.ts           |  2 +-
 .../pipelineElementConfigurationTemplate.ts        |  2 +-
 .../userManagement/testGroupManagement.spec.ts     |  2 +-
 .../userManagement/testUserRolePipeline.spec.ts    |  2 +-
 .../basic-nav-tabs/basic-nav-tabs.component.html   |  1 +
 .../start-adapter-configuration.component.html     |  1 +
 .../adapter-started-dialog.component.ts            | 47 ++++++----
 .../configuration-code-panel.component.html        |  2 +
 .../live-preview-table.component.html              | 11 ++-
 39 files changed, 778 insertions(+), 123 deletions(-)

diff --git 
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
 
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
index 62c514b1e6..5c42478431 100644
--- 
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
+++ 
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
@@ -53,10 +53,11 @@ public class AdapterMasterManagement {
 
   private final DataStreamResourceManager dataStreamResourceManager;
 
-  public AdapterMasterManagement(IAdapterStorage adapterInstanceStorage,
-                                 AdapterResourceManager adapterResourceManager,
-                                 DataStreamResourceManager 
dataStreamResourceManager,
-                                 AdapterMetrics adapterMetrics
+  public AdapterMasterManagement(
+      IAdapterStorage adapterInstanceStorage,
+      AdapterResourceManager adapterResourceManager,
+      DataStreamResourceManager dataStreamResourceManager,
+      AdapterMetrics adapterMetrics
   ) {
     this.adapterInstanceStorage = adapterInstanceStorage;
     this.adapterMetrics = adapterMetrics;
@@ -64,28 +65,40 @@ public class AdapterMasterManagement {
     this.dataStreamResourceManager = dataStreamResourceManager;
   }
 
-  public void addAdapter(AdapterDescription ad,
-                           String adapterElementId,
-                           String principalSid)
+  public void addAdapter(
+      AdapterDescription adapterDescription,
+      String adapterId,
+      String principalSid
+  )
       throws AdapterException {
 
-    // Create elementId for adapter
+    // Create elementId for datastream
     var dataStreamElementId = 
ElementIdGenerator.makeElementId(SpDataStream.class);
-    ad.setElementId(adapterElementId);
-    ad.setCreatedAt(System.currentTimeMillis());
-    ad.setCorrespondingDataStreamElementId(dataStreamElementId);
+    adapterDescription.setElementId(adapterId);
+    adapterDescription.setCreatedAt(System.currentTimeMillis());
+    
adapterDescription.setCorrespondingDataStreamElementId(dataStreamElementId);
 
     // Add EventGrounding to AdapterDescription
     var eventGrounding = GroundingUtils.createEventGrounding();
-    ad.setEventGrounding(eventGrounding);
+    adapterDescription.setEventGrounding(eventGrounding);
 
-    this.adapterResourceManager.encryptAndCreate(ad);
+    this.adapterResourceManager.encryptAndCreate(adapterDescription);
 
-    // Create stream
-    var storedDescription = new 
SourcesManagement().createAdapterDataStream(ad, dataStreamElementId);
-    storedDescription.setCorrespondingAdapterId(adapterElementId);
+    // Stream is only created if the adpater is successfully stored
+    createDataStreamForAdapter(adapterDescription, adapterId, 
dataStreamElementId, principalSid);
+  }
+
+  private void createDataStreamForAdapter(
+      AdapterDescription adapterDescription,
+      String adapterId,
+      String streamId,
+      String principalSid
+  ) throws AdapterException {
+    var storedDescription = new SourcesManagement()
+        .createAdapterDataStream(adapterDescription, streamId);
+    storedDescription.setCorrespondingAdapterId(adapterId);
     installDataSource(storedDescription, principalSid, true);
-    LOG.info("Install source (source URL: {} in backend", ad.getElementId());
+    LOG.info("Install source (source URL: {} in backend", 
adapterDescription.getElementId());
   }
 
   public AdapterDescription getAdapter(String elementId) throws 
AdapterException {
@@ -163,7 +176,8 @@ public class AdapterMasterManagement {
       var baseUrl = new 
ExtensionsServiceEndpointGenerator().getEndpointBaseUrl(
           ad.getAppId(),
           SpServiceUrlProvider.ADAPTER,
-          ad.getDeploymentConfiguration().getDesiredServiceTags()
+          ad.getDeploymentConfiguration()
+            .getDesiredServiceTags()
       );
 
       // Update selected endpoint URL of adapter
@@ -182,9 +196,11 @@ public class AdapterMasterManagement {
     }
   }
 
-  private void installDataSource(SpDataStream stream,
-                                 String principalSid,
-                                 boolean publicElement) throws 
AdapterException {
+  private void installDataSource(
+      SpDataStream stream,
+      String principalSid,
+      boolean publicElement
+  ) throws AdapterException {
     try {
       new DataStreamVerifier(stream).verifyAndAdd(principalSid, publicElement);
     } catch (SepaParseException e) {
diff --git 
a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
 
b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
index 6d920fb751..e1e18324ce 100644
--- 
a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
+++ 
b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
@@ -36,12 +36,12 @@ import static org.mockito.Mockito.when;
 public class AdapterMasterManagementTest {
 
   @Test
-  public void getAdapterFailNull() {
-    AdapterInstanceStorageImpl adapterStorage = 
mock(AdapterInstanceStorageImpl.class);
-    AdapterResourceManager resourceManager = 
mock(AdapterResourceManager.class);
+  public void getAdapter_FailNull() {
+    var adapterStorage = mock(AdapterInstanceStorageImpl.class);
+    var resourceManager = mock(AdapterResourceManager.class);
     when(adapterStorage.findAll()).thenReturn(null);
 
-    AdapterMasterManagement adapterMasterManagement =
+    var adapterMasterManagement =
         new AdapterMasterManagement(
             adapterStorage,
             resourceManager,
@@ -53,13 +53,13 @@ public class AdapterMasterManagementTest {
   }
 
   @Test
-  public void getAdapterFail() {
-    List<AdapterDescription> adapterDescriptions = List.of(new 
AdapterDescription());
-    AdapterInstanceStorageImpl adapterStorage = 
mock(AdapterInstanceStorageImpl.class);
-    AdapterResourceManager resourceManager = 
mock(AdapterResourceManager.class);
+  public void getAdapter_Fail() {
+    var adapterDescriptions = List.of(new AdapterDescription());
+    var adapterStorage = mock(AdapterInstanceStorageImpl.class);
+    var resourceManager = mock(AdapterResourceManager.class);
     when(adapterStorage.findAll()).thenReturn(adapterDescriptions);
 
-    AdapterMasterManagement adapterMasterManagement =
+    var adapterMasterManagement =
         new AdapterMasterManagement(
             adapterStorage,
             resourceManager,
@@ -71,10 +71,10 @@ public class AdapterMasterManagementTest {
   }
 
   @Test
-  public void getAllAdaptersSuccess() throws AdapterException {
-    List<AdapterDescription> adapterDescriptions = List.of(new 
AdapterDescription());
-    AdapterInstanceStorageImpl adapterStorage = 
mock(AdapterInstanceStorageImpl.class);
-    AdapterResourceManager resourceManager = 
mock(AdapterResourceManager.class);
+  public void getAllAdapters_Success() throws AdapterException {
+    var adapterDescriptions = List.of(new AdapterDescription());
+    var adapterStorage = mock(AdapterInstanceStorageImpl.class);
+    var resourceManager = mock(AdapterResourceManager.class);
     when(adapterStorage.findAll()).thenReturn(adapterDescriptions);
 
     AdapterMasterManagement adapterMasterManagement =
@@ -91,12 +91,12 @@ public class AdapterMasterManagementTest {
   }
 
   @Test
-  public void getAllAdaptersFail() {
-    AdapterInstanceStorageImpl adapterStorage = 
mock(AdapterInstanceStorageImpl.class);
-    AdapterResourceManager resourceManager = 
mock(AdapterResourceManager.class);
+  public void getAllAdapters_Fail() {
+    var adapterStorage = mock(AdapterInstanceStorageImpl.class);
+    var resourceManager = mock(AdapterResourceManager.class);
     when(adapterStorage.findAll()).thenReturn(null);
 
-    AdapterMasterManagement adapterMasterManagement =
+    var adapterMasterManagement =
         new AdapterMasterManagement(
             adapterStorage,
             resourceManager,
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/message/Notifications.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/message/Notifications.java
index 4e14af9262..965a84257d 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/message/Notifications.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/message/Notifications.java
@@ -44,8 +44,12 @@ public class Notifications {
     return new ErrorMessage(new Notification(type.name(), type.description()));
   }
 
+  public static ErrorMessage error(String message, String description) {
+    return new ErrorMessage(new Notification(message, description));
+  }
+
   public static ErrorMessage error(String message) {
-    return new ErrorMessage(new Notification(message, ""));
+    return error(message, "");
   }
 
   public static ErrorMessage error(NotificationType type, String info) {
diff --git 
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AdapterResourceManager.java
 
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AdapterResourceManager.java
index 72c77121aa..8e3d4d4a85 100644
--- 
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AdapterResourceManager.java
+++ 
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AdapterResourceManager.java
@@ -17,6 +17,7 @@
  */
 package org.apache.streampipes.resource.management;
 
+import org.apache.streampipes.commons.exceptions.connect.AdapterException;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.util.Cloner;
 import org.apache.streampipes.resource.management.secret.SecretProvider;
@@ -30,7 +31,8 @@ public class AdapterResourceManager extends 
AbstractResourceManager<IAdapterStor
   }
 
   public AdapterResourceManager() {
-    
super(StorageDispatcher.INSTANCE.getNoSqlStore().getAdapterInstanceStorage());
+    super(StorageDispatcher.INSTANCE.getNoSqlStore()
+                                    .getAdapterInstanceStorage());
   }
 
   /**
@@ -39,10 +41,15 @@ public class AdapterResourceManager extends 
AbstractResourceManager<IAdapterStor
    * @param adapterDescription input adapter description
    * @return the id of the created adapter
    */
-  public String encryptAndCreate(AdapterDescription adapterDescription) {
-    AdapterDescription encryptedAdapterDescription = 
cloneAndEncrypt(adapterDescription);
+  public String encryptAndCreate(AdapterDescription adapterDescription) throws 
AdapterException {
+    var encryptedAdapterDescription = cloneAndEncrypt(adapterDescription);
     encryptedAdapterDescription.setRev(null);
-    return db.persist(encryptedAdapterDescription).v;
+
+    try {
+      return db.persist(encryptedAdapterDescription).v;
+    } catch (org.lightcouch.DocumentConflictException e) {
+      throw new AdapterException("Conflict occurred while creating the 
adapter", e);
+    }
   }
 
   /**
@@ -50,8 +57,15 @@ public class AdapterResourceManager extends 
AbstractResourceManager<IAdapterStor
    *
    * @param adapterDescription input adapter description
    */
-  public void encryptAndUpdate(AdapterDescription adapterDescription) {
-    db.updateElement(cloneAndEncrypt(adapterDescription));
+  public void encryptAndUpdate(AdapterDescription adapterDescription) throws 
AdapterException {
+    try {
+      db.updateElement(cloneAndEncrypt(adapterDescription));
+    } catch (org.lightcouch.DocumentConflictException e) {
+      throw new AdapterException(
+          "Conflict occurred while editing the adapter with id: 
%s".formatted(adapterDescription.getElementId()),
+          e
+      );
+    }
   }
 
   public void delete(String elementId) {
@@ -63,7 +77,8 @@ public class AdapterResourceManager extends 
AbstractResourceManager<IAdapterStor
    */
   private AdapterDescription cloneAndEncrypt(AdapterDescription 
adapterDescription) {
     AdapterDescription encryptedAdapterDescription = new 
Cloner().adapterDescription(adapterDescription);
-    SecretProvider.getEncryptionService().apply(encryptedAdapterDescription);
+    SecretProvider.getEncryptionService()
+                  .apply(encryptedAdapterDescription);
     return encryptedAdapterDescription;
   }
 
diff --git 
a/streampipes-resource-management/src/test/java/org/apache/streampipes/resource/management/AdapterResourceManagerTest.java
 
b/streampipes-resource-management/src/test/java/org/apache/streampipes/resource/management/AdapterResourceManagerTest.java
index d815855490..d4616713da 100644
--- 
a/streampipes-resource-management/src/test/java/org/apache/streampipes/resource/management/AdapterResourceManagerTest.java
+++ 
b/streampipes-resource-management/src/test/java/org/apache/streampipes/resource/management/AdapterResourceManagerTest.java
@@ -18,25 +18,59 @@
 
 package org.apache.streampipes.resource.management;
 
+import org.apache.streampipes.commons.exceptions.connect.AdapterException;
+import org.apache.streampipes.model.Tuple2;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.storage.api.IAdapterStorage;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 public class AdapterResourceManagerTest {
 
+  private IAdapterStorage storage;
+  private AdapterResourceManager adapterResourceManager;
+
+  @BeforeEach
+  void setUp() {
+    storage = mock(IAdapterStorage.class);
+    adapterResourceManager = new AdapterResourceManager(storage);
+  }
+
   @Test
-  public void encryptAndUpdateValidateDescriptionStored() {
+  public void encryptAndUpdate_ValidateDescriptionStored() throws 
AdapterException {
 
-    IAdapterStorage storage = mock(IAdapterStorage.class);
-    AdapterResourceManager adapterResourceManager = new 
AdapterResourceManager(storage);
     adapterResourceManager.encryptAndUpdate(new AdapterDescription());
 
     verify(storage, times(1)).updateElement(any());
   }
+
+  @Test
+  void encryptAndCreate_ReturnsIdOnSuccess() throws AdapterException {
+    var id = "adapterId";
+
+    when(storage.persist(any())).thenReturn(new Tuple2<>(true, id));
+    var result = adapterResourceManager.encryptAndCreate(new 
AdapterDescription());
+
+    verify(storage, times(1)).persist(any());
+    assertEquals(id, result);
+  }
+
+  @Test
+  void encryptAndCreate_ThrowsAdapterExceptionOnConflict() {
+
+    doThrow(new 
org.lightcouch.DocumentConflictException("Conflict")).when(storage).persist(any());
+
+    assertThrows(AdapterException.class, () -> 
adapterResourceManager.encryptAndCreate(new AdapterDescription()));
+  }
+
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
index b972aaa7eb..372769a792 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
@@ -40,6 +40,7 @@ import 
org.apache.streampipes.rest.shared.constants.SpMediaType;
 import org.apache.streampipes.storage.api.IPipelineStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -115,7 +116,7 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
       updateManager.updateAdapter(adapterDescription);
     } catch (AdapterException e) {
       LOG.error("Error while updating adapter with id {}", 
adapterDescription.getElementId(), e);
-      return ok(Notifications.error(e.getMessage()));
+      return ok(Notifications.error(e.getMessage(), 
ExceptionUtils.getStackTrace(e)));
     }
 
     return ok(Notifications.success(adapterDescription.getElementId()));
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
index 88424c2256..0e51f00927 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
@@ -37,6 +37,7 @@ import 
org.apache.streampipes.storage.management.StorageDispatcher;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -58,7 +59,7 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
   public CompactAdapterResource() {
     super(() -> new AdapterMasterManagement(
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getAdapterInstanceStorage(),
+                                  .getAdapterInstanceStorage(),
         new SpResourceManager().manageAdapters(),
         new SpResourceManager().manageDataStreams(),
         AdapterMetricsManager.INSTANCE.getAdapterMetrics()
@@ -82,11 +83,23 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
     var adapterDescription = getGeneratedAdapterDescription(compactAdapter);
     var principalSid = getAuthenticatedUserSid();
 
+    var adapterId = adapterDescription.getElementId();
+
     try {
-      var adapterId = adapterDescription.getElementId();
       managementService.addAdapter(adapterDescription, adapterId, 
principalSid);
+    } catch (AdapterException e) {
+      LOG.error(
+          "Error while storing the adapterDescription with appId {}. An 
adapter with the given id already exists.",
+          adapterDescription.getAppId(), e
+      );
+      return ResponseEntity.status(HttpStatus.CONFLICT)
+                           .body(Notifications.error(e.getMessage()));
+    }
+
+    try {
       if (compactAdapter.createOptions() != null) {
-        if (compactAdapter.createOptions().persist()) {
+        if (compactAdapter.createOptions()
+                          .persist()) {
           var storedAdapter = managementService.getAdapter(adapterId);
           var status = new PersistPipelineHandler(
               getNoSqlStorage().getPipelineTemplateStorage(),
@@ -96,7 +109,8 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
               getAuthenticatedUserSid()
           ).createAndStartPersistPipeline(storedAdapter);
         }
-        if (compactAdapter.createOptions().start()) {
+        if (compactAdapter.createOptions()
+                          .start()) {
           managementService.startStreamAdapter(adapterId);
         }
       }
@@ -143,8 +157,10 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
     return new 
CompactAdapterManagement(generators).convertToAdapterDescription(compactAdapter);
   }
 
-  private AdapterDescription getGeneratedAdapterDescription(CompactAdapter 
compactAdapter,
-                                                            AdapterDescription 
existingAdapter) throws Exception {
+  private AdapterDescription getGeneratedAdapterDescription(
+      CompactAdapter compactAdapter,
+      AdapterDescription existingAdapter
+  ) throws Exception {
     var generators = adapterGenerationSteps.getGenerators();
     return new 
CompactAdapterManagement(generators).convertToAdapterDescription(compactAdapter,
 existingAdapter);
   }
diff --git a/ui/cypress/fixtures/connect/compact/machineDataSimulator.yml 
b/ui/cypress/fixtures/connect/compact/machineDataSimulator.yml
new file mode 100644
index 0000000000..128b249ca6
--- /dev/null
+++ b/ui/cypress/fixtures/connect/compact/machineDataSimulator.yml
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+id: sp:adapterdescription:4pxl2w
+name: Test
+appId: org.apache.streampipes.connect.iiot.adapters.simulator.machine
+configuration:
+    - wait-time-ms: '1000'
+    - selected-simulator-option: flowrate
+createOptions:
+    persist: false
+    start: false
diff --git a/ui/cypress/support/builder/CompactAdapterBuilder.ts 
b/ui/cypress/support/builder/CompactAdapterBuilder.ts
new file mode 100644
index 0000000000..2325985032
--- /dev/null
+++ b/ui/cypress/support/builder/CompactAdapterBuilder.ts
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+import { CompactAdapter } from 
'../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
+
+export class CompactAdapterBuilder {
+    private compactAdapter: CompactAdapter;
+
+    constructor() {
+        this.compactAdapter = new CompactAdapter();
+        this.compactAdapter.configuration = [];
+        this.compactAdapter.createOptions = {
+            persist: false,
+            start: false,
+        };
+        this.compactAdapter.transform = {
+            rename: {},
+            measurementUnit: {},
+        };
+    }
+
+    public static create(appId: string) {
+        const builder = new CompactAdapterBuilder();
+        builder.compactAdapter.appId = appId;
+        return builder;
+    }
+
+    // Optional parameter, when not set a random id will be generated
+    public setId(id: string) {
+        this.compactAdapter.id = id;
+        return this;
+    }
+
+    public setName(name: string) {
+        this.compactAdapter.name = name;
+        return this;
+    }
+
+    public setDescription(description: string) {
+        this.compactAdapter.description = description;
+        return this;
+    }
+
+    public withRename(from: string, to: string) {
+        this.compactAdapter.transform.rename[from] = to;
+        return this;
+    }
+
+    public withMeasurementUnit(property: string, unit: string) {
+        this.compactAdapter.transform.measurementUnit[property] = unit;
+        return this;
+    }
+
+    public addConfiguration(key: string, value: string) {
+        const configuration = { [key]: value };
+        this.compactAdapter.configuration.push(configuration);
+        return this;
+    }
+
+    public setPersist() {
+        this.compactAdapter.createOptions.persist = true;
+        return this;
+    }
+
+    public setStart() {
+        this.compactAdapter.createOptions.start = true;
+        return this;
+    }
+
+    public build() {
+        if (!this.compactAdapter.id) {
+            this.compactAdapter.id =
+                'sp:adapterdescription:' +
+                Math.random().toString(36).substring(7);
+        }
+        return this.compactAdapter;
+    }
+}
diff --git a/ui/cypress/support/utils/CompactUtils.ts 
b/ui/cypress/support/utils/CompactUtils.ts
new file mode 100644
index 0000000000..38df176d86
--- /dev/null
+++ b/ui/cypress/support/utils/CompactUtils.ts
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+export class CompactUtils {
+    public static ymlConfiguration() {
+        return cy.dataCy('yaml-configuration', { timeout: 5000 });
+    }
+
+    public static jsonConfiguration() {
+        return cy.dataCy('json-configuration', { timeout: 5000 });
+    }
+}
diff --git a/ui/cypress/support/utils/GeneralUtils.ts 
b/ui/cypress/support/utils/GeneralUtils.ts
new file mode 100644
index 0000000000..8db505e32b
--- /dev/null
+++ b/ui/cypress/support/utils/GeneralUtils.ts
@@ -0,0 +1,23 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+export class GeneralUtils {
+    public static tab(identifier: string) {
+        return cy.dataCy(`tab-${identifier}`).click();
+    }
+}
diff --git a/ui/cypress/support/utils/ProcessingElementTestUtils.ts 
b/ui/cypress/support/utils/ProcessingElementTestUtils.ts
index f2607a112b..6340635b48 100644
--- a/ui/cypress/support/utils/ProcessingElementTestUtils.ts
+++ b/ui/cypress/support/utils/ProcessingElementTestUtils.ts
@@ -18,7 +18,7 @@
 
 import { FileManagementUtils } from './FileManagementUtils';
 import { ConnectUtils } from './connect/ConnectUtils';
-import { PipelineUtils } from './PipelineUtils';
+import { PipelineUtils } from './pipeline/PipelineUtils';
 import { DataLakeUtils } from './datalake/DataLakeUtils';
 import { PipelineBuilder } from '../builder/PipelineBuilder';
 import { PipelineElementBuilder } from '../builder/PipelineElementBuilder';
diff --git a/ui/cypress/support/utils/ThirdPartyIntegrationUtils.ts 
b/ui/cypress/support/utils/ThirdPartyIntegrationUtils.ts
index a9229a9a05..09a871c6fb 100644
--- a/ui/cypress/support/utils/ThirdPartyIntegrationUtils.ts
+++ b/ui/cypress/support/utils/ThirdPartyIntegrationUtils.ts
@@ -18,7 +18,7 @@
 
 import { ConnectUtils } from './connect/ConnectUtils';
 import { PipelineBuilder } from '../builder/PipelineBuilder';
-import { PipelineUtils } from './PipelineUtils';
+import { PipelineUtils } from './pipeline/PipelineUtils';
 import { PipelineElementInput } from '../model/PipelineElementInput';
 import { AdapterInput } from '../model/AdapterInput';
 import { AdapterBuilder } from '../builder/AdapterBuilder';
diff --git a/ui/cypress/support/utils/connect/CompactAdapterUtils.ts 
b/ui/cypress/support/utils/connect/CompactAdapterUtils.ts
new file mode 100644
index 0000000000..43757f580c
--- /dev/null
+++ b/ui/cypress/support/utils/connect/CompactAdapterUtils.ts
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+import { CompactAdapter } from 
'../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
+import { CompactAdapterBuilder } from '../../builder/CompactAdapterBuilder';
+
+export class CompactAdapterUtils {
+    /**
+     * Stores a compact adapter by sending a POST request to the backend.
+     *
+     * @param {CompactAdapter} compactAdapter - The compact adapter to be 
stored.
+     * @param {boolean} [failOnStatusCode=true] - Whether to fail the request 
on a non-2xx status code.
+     * @returns {Cypress.Chainable} - The Cypress chainable object 
representing the request.
+     */
+    public static storeCompactAdapter(
+        compactAdapter: CompactAdapter,
+        failOnStatusCode: boolean = true,
+    ): Cypress.Chainable {
+        return this.postCompactAdapterRequest(
+            'application/json',
+            compactAdapter,
+            failOnStatusCode,
+        );
+    }
+
+    /**
+     * Stores a compact YAML adapter by sending a POST request to the backend.
+     *
+     * @param {string} body - The YAML string representing the compact adapter.
+     * @returns {Cypress.Chainable} - The Cypress chainable object 
representing the request.
+     */
+    public static storeCompactYmlAdapter(body: string) {
+        return this.postCompactAdapterRequest('application/yml', body);
+    }
+
+    private static postCompactAdapterRequest(
+        contentType: string,
+        body: any,
+        failOnStatusCode = true,
+    ) {
+        const token = window.localStorage.getItem('auth-token');
+        return cy.request({
+            method: 'POST',
+            url: '/streampipes-backend/api/v2/connect/compact-adapters',
+            body: body,
+            failOnStatusCode: failOnStatusCode,
+            headers: {
+                'Accept': contentType,
+                'Content-Type': contentType,
+                'Authorization': `Bearer ${token}`,
+            },
+        });
+    }
+
+    /**
+     * Creates a CompactAdapterBuilder instance configured for a machine data 
simulator.
+     */
+    public static getMachineDataSimulator(): CompactAdapterBuilder {
+        return CompactAdapterBuilder.create(
+            'org.apache.streampipes.connect.iiot.adapters.simulator.machine',
+        )
+            .setName('Test')
+            .addConfiguration('wait-time-ms', '1000')
+            .addConfiguration('selected-simulator-option', 'flowrate');
+    }
+}
diff --git a/ui/cypress/support/utils/connect/ConnectBtns.ts 
b/ui/cypress/support/utils/connect/ConnectBtns.ts
index 20bfd696c5..ea8b2d82c3 100644
--- a/ui/cypress/support/utils/connect/ConnectBtns.ts
+++ b/ui/cypress/support/utils/connect/ConnectBtns.ts
@@ -17,7 +17,11 @@
  */
 export class ConnectBtns {
     public static detailsAdapter() {
-        return cy.dataCy('details-adapter');
+        return cy.dataCy('details-adapter', { timeout: 10000 });
+    }
+
+    public static deleteAdapter() {
+        return cy.dataCy('delete-adapter', { timeout: 10000 });
     }
 
     public static editAdapter() {
@@ -69,6 +73,10 @@ export class ConnectBtns {
         return cy.dataCy('stop-all-adapters-btn');
     }
 
+    public static showCodeCheckbox() {
+        return cy.dataCy('show-code-checkbox');
+    }
+
     // ========================================================================
 
     // =====================  Event Schema buttons  ==========================
diff --git a/ui/cypress/support/utils/connect/ConnectUtils.ts 
b/ui/cypress/support/utils/connect/ConnectUtils.ts
index aaeccff82c..0a0eae22c1 100644
--- a/ui/cypress/support/utils/connect/ConnectUtils.ts
+++ b/ui/cypress/support/utils/connect/ConnectUtils.ts
@@ -23,7 +23,7 @@ import { DataLakeUtils } from '../datalake/DataLakeUtils';
 import { ConnectBtns } from './ConnectBtns';
 import { AdapterBuilder } from '../../builder/AdapterBuilder';
 import { UserUtils } from '../UserUtils';
-import { PipelineUtils } from '../PipelineUtils';
+import { PipelineUtils } from '../pipeline/PipelineUtils';
 
 export class ConnectUtils {
     public static testAdapter(
@@ -76,9 +76,11 @@ export class ConnectUtils {
             );
         }
 
-        ConnectEventSchemaUtils.markPropertyAsTimestamp(
-            adapterConfiguration.timestampProperty,
-        );
+        if (adapterConfiguration.timestampProperty) {
+            ConnectEventSchemaUtils.markPropertyAsTimestamp(
+                adapterConfiguration.timestampProperty,
+            );
+        }
 
         ConnectEventSchemaUtils.finishEventSchemaConfiguration();
     }
@@ -356,6 +358,12 @@ export class ConnectUtils {
         ConnectUtils.validateEventsInPreview(amountOfProperties);
     }
 
+    public static getLivePreviewValue(runtimeName: string) {
+        return cy.dataCy(`live-preview-value-${runtimeName}`, {
+            timeout: 10000,
+        });
+    }
+
     public static validateEventsInPreview(amountOfProperties: number) {
         // View data
         ConnectBtns.detailsAdapter().click();
@@ -370,11 +378,25 @@ export class ConnectUtils {
             amountOfProperties,
         );
 
-        cy.wait(1000);
+        cy.dataCy('live-preview-table-no-data', { timout: 1000 }).should(
+            'not.exist',
+        );
+    }
+
+    /**
+     * Validates the event schema for an adapter by checking the amount of 
properties
+     * and the runtime names of the event properties
+     * @param runtimeNames runtime names of the event properties
+     */
+    public static validateEventSchema(runtimeNames: string[]) {
+        ConnectUtils.goToConnect();
+        ConnectBtns.detailsAdapter().click();
+
+        cy.get('tr.mat-mdc-row').should('have.length', runtimeNames.length);
 
-        cy.dataCy('live-preview-table-value')
-            .invoke('text')
-            .then(text => expect(text).not.to.include('no data'));
+        runtimeNames.forEach(name => {
+            cy.get('td.mat-column-runtimeName').contains(name).should('exist');
+        });
     }
 
     public static tearDownPreprocessingRuleTest(
@@ -403,4 +425,21 @@ export class ConnectUtils {
         // Close dialog
         cy.get('button').contains('Close').parent().click();
     }
+
+    public static validateAdapterIsRunning() {
+        ConnectUtils.goToConnect();
+        ConnectBtns.startAdapter().should('have.length', 0);
+        ConnectBtns.stopAdapter().should('have.length', 1);
+    }
+
+    public static validateAdapterIsStopped() {
+        ConnectUtils.goToConnect();
+        ConnectBtns.startAdapter().should('have.length', 1);
+        ConnectBtns.stopAdapter().should('have.length', 0);
+    }
+
+    public static checkAmountOfAdapters(amount: number) {
+        ConnectUtils.goToConnect();
+        ConnectBtns.deleteAdapter().should('have.length', amount);
+    }
 }
diff --git a/ui/cypress/support/utils/pipeline/PipelineBtns.ts 
b/ui/cypress/support/utils/pipeline/PipelineBtns.ts
new file mode 100644
index 0000000000..6ace82220f
--- /dev/null
+++ b/ui/cypress/support/utils/pipeline/PipelineBtns.ts
@@ -0,0 +1,23 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+export class PipelineBtns {
+    public static deletePipeline() {
+        return cy.dataCy('delete-pipeline', { timeout: 10000 });
+    }
+}
diff --git a/ui/cypress/support/utils/PipelineUtils.ts 
b/ui/cypress/support/utils/pipeline/PipelineUtils.ts
similarity index 72%
rename from ui/cypress/support/utils/PipelineUtils.ts
rename to ui/cypress/support/utils/pipeline/PipelineUtils.ts
index b901e225de..0fa9ce4443 100644
--- a/ui/cypress/support/utils/PipelineUtils.ts
+++ b/ui/cypress/support/utils/pipeline/PipelineUtils.ts
@@ -1,25 +1,26 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
  *
  */
 
-import { PipelineInput } from '../model/PipelineInput';
-import { StaticPropertyUtils } from './userInput/StaticPropertyUtils';
-import { OutputStrategyUtils } from './OutputStrategyUtils';
-import { PipelineElementInput } from '../model/PipelineElementInput';
+import { PipelineInput } from '../../model/PipelineInput';
+import { StaticPropertyUtils } from '../userInput/StaticPropertyUtils';
+import { OutputStrategyUtils } from '../OutputStrategyUtils';
+import { PipelineElementInput } from '../../model/PipelineElementInput';
+import { PipelineBtns } from './PipelineBtns';
 
 export class PipelineUtils {
     public static addPipeline(pipelineInput: PipelineInput) {
@@ -131,21 +132,18 @@ export class PipelineUtils {
     }
 
     public static checkAmountOfPipelinesPipeline(amount: number) {
-        cy.visit('#/pipelines');
-        cy.dataCy('delete-pipeline').should('have.length', amount);
+        PipelineUtils.goToPipelines();
+        PipelineBtns.deletePipeline().should('have.length', amount);
     }
 
     public static deletePipeline() {
         // Delete pipeline
-        cy.visit('#/pipelines');
-        cy.dataCy('delete-pipeline').should('have.length', 1);
-        cy.dataCy('delete-pipeline').click({ force: true });
+        PipelineUtils.goToPipelines();
+        PipelineBtns.deletePipeline().should('have.length', 1);
+        PipelineBtns.deletePipeline().click({ force: true });
 
         cy.dataCy('sp-pipeline-stop-and-delete').click();
 
-        cy.dataCy('delete-pipeline', { timeout: 10000 }).should(
-            'have.length',
-            0,
-        );
+        PipelineBtns.deletePipeline().should('have.length', 0);
     }
 }
diff --git a/ui/cypress/tests/connect/compact/addCompactAdapter.spec.ts 
b/ui/cypress/tests/connect/compact/addCompactAdapter.spec.ts
new file mode 100644
index 0000000000..c19e345f8d
--- /dev/null
+++ b/ui/cypress/tests/connect/compact/addCompactAdapter.spec.ts
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
+import { CompactAdapterUtils } from 
'../../../support/utils/connect/CompactAdapterUtils';
+import { PipelineUtils } from '../../../support/utils/pipeline/PipelineUtils';
+
+describe('Add Compact Adapters', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Add an adapter via the compact API. Do not start', () => {
+        const compactAdapter =
+            CompactAdapterUtils.getMachineDataSimulator().build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(() => {
+            ConnectUtils.validateAdapterIsStopped();
+
+            PipelineUtils.checkAmountOfPipelinesPipeline(0);
+        });
+    });
+
+    it('Add an adapter via the compact API. Start Adapter', () => {
+        const compactAdapter = CompactAdapterUtils.getMachineDataSimulator()
+            .setStart()
+            .build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(() => {
+            ConnectUtils.validateAdapterIsRunning();
+
+            PipelineUtils.checkAmountOfPipelinesPipeline(0);
+        });
+    });
+
+    it('Add an adapter via the compact API. Start Adapter and start persist 
pipeline', () => {
+        const compactAdapter = CompactAdapterUtils.getMachineDataSimulator()
+            .setStart()
+            .setPersist()
+            .build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(() => {
+            ConnectUtils.validateAdapterIsRunning();
+
+            PipelineUtils.checkAmountOfPipelinesPipeline(1);
+        });
+    });
+
+    it('Add an adapter via the compact API via yml API.', () => {
+        cy.readFile(
+            'cypress/fixtures/connect/compact/machineDataSimulator.yml',
+        ).then(ymlDescription => {
+            CompactAdapterUtils.storeCompactYmlAdapter(ymlDescription).then(
+                () => {
+                    ConnectUtils.validateAdapterIsStopped();
+                },
+            );
+        });
+    });
+
+    it('Ensure correct error code when adapter with the same id already 
exists', () => {
+        const compactAdapter = CompactAdapterUtils.getMachineDataSimulator()
+            .setStart()
+            .setPersist()
+            .build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(
+            response => {
+                expect(response.status).to.equal(200);
+                ConnectUtils.checkAmountOfAdapters(1);
+
+                // Store the same adapter a second time and validate that 
resource returns status of conflict
+                CompactAdapterUtils.storeCompactAdapter(
+                    compactAdapter,
+                    false,
+                ).then(response => {
+                    expect(response.status).to.equal(409);
+
+                    ConnectUtils.checkAmountOfAdapters(1);
+                });
+            },
+        );
+    });
+});
diff --git 
a/ui/cypress/tests/connect/compact/compactAdapterWithTransformation.spec.ts 
b/ui/cypress/tests/connect/compact/compactAdapterWithTransformation.spec.ts
new file mode 100644
index 0000000000..4af2f359e2
--- /dev/null
+++ b/ui/cypress/tests/connect/compact/compactAdapterWithTransformation.spec.ts
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
+import { CompactAdapterUtils } from 
'../../../support/utils/connect/CompactAdapterUtils';
+import { ConnectBtns } from '../../../support/utils/connect/ConnectBtns';
+
+describe('Add Compact Adapters', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Add an adapter and rename a property', () => {
+        const newPropertyName = 'temperature_renamed';
+        const compactAdapter = CompactAdapterUtils.getMachineDataSimulator()
+            .withRename('temperature', newPropertyName)
+            .setStart()
+            .build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(() => {
+            const runtimeNames = [
+                'density',
+                'mass_flow',
+                'sensor_fault_flags',
+                'sensorId',
+                newPropertyName,
+                'timestamp',
+                'volume_flow',
+            ];
+
+            ConnectUtils.validateEventSchema(runtimeNames);
+        });
+    });
+
+    it('Add an adapter and change measurement unit', () => {
+        const compactAdapter = CompactAdapterUtils.getMachineDataSimulator()
+            .withMeasurementUnit(
+                'temperature',
+                'http://qudt.org/vocab/unit#DegreeFahrenheit',
+            )
+            .setStart()
+            .build();
+
+        CompactAdapterUtils.storeCompactAdapter(compactAdapter).then(() => {
+            ConnectUtils.goToConnect();
+            ConnectBtns.detailsAdapter().click();
+
+            // This assertion works because the original value is below 100
+            // with the transformation the value is above 100
+            ConnectUtils.getLivePreviewValue('temperature')
+                .invoke('text')
+                .then(text => {
+                    const value = parseFloat(text.trim());
+                    expect(value).to.be.greaterThan(100);
+                });
+        });
+    });
+});
diff --git a/ui/cypress/tests/connect/compact/uiConfiguration.spec.ts 
b/ui/cypress/tests/connect/compact/uiConfiguration.spec.ts
new file mode 100644
index 0000000000..798d8a8caf
--- /dev/null
+++ b/ui/cypress/tests/connect/compact/uiConfiguration.spec.ts
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
+import { AdapterBuilder } from '../../../support/builder/AdapterBuilder';
+import { ConnectBtns } from '../../../support/utils/connect/ConnectBtns';
+import { GeneralUtils } from '../../../support/utils/GeneralUtils';
+import { CompactUtils } from '../../../support/utils/CompactUtils';
+
+describe('Test Compact Adapters', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Validate that code for existing adapter is displayed correctly', () => 
{
+        const adapterInput = AdapterBuilder.create('Machine_Data_Simulator')
+            .setName('Machine Data Simulator Test')
+            .addInput('input', 'wait-time-ms', '1000')
+            .build();
+
+        ConnectUtils.addAdapter(adapterInput);
+
+        // Validate code editor in start dialog
+        ConnectBtns.showCodeCheckbox().parent().click();
+        validateCodeEditor();
+
+        ConnectUtils.startAdapter(adapterInput);
+
+        // Validate code editor in adapter details
+        ConnectBtns.detailsAdapter().click();
+        GeneralUtils.tab('Code');
+        validateCodeEditor();
+    });
+
+    const validateCodeEditor = () => {
+        CompactUtils.ymlConfiguration().should('be.visible');
+        cy.contains('span', 'JSON').click();
+        CompactUtils.jsonConfiguration().should('be.visible');
+    };
+});
diff --git 
a/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts 
b/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts
index 29c854cb23..a11332ac9e 100644
--- a/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts
+++ b/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts
@@ -20,7 +20,7 @@ import { ConnectUtils } from 
'../../support/utils/connect/ConnectUtils';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { UserUtils } from '../../support/utils/UserUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 
 const adapterName = 'simulator';
 
diff --git a/ui/cypress/tests/connect/editAdapter.smoke.spec.ts 
b/ui/cypress/tests/connect/editAdapter.smoke.spec.ts
index 214e8433c8..a1d20139eb 100644
--- a/ui/cypress/tests/connect/editAdapter.smoke.spec.ts
+++ b/ui/cypress/tests/connect/editAdapter.smoke.spec.ts
@@ -57,6 +57,8 @@ describe('Test Edit Adapter', () => {
 
         cy.dataCy('sp-adapter-name').clear().type(newAdapterName);
 
+        // This wait is required to ensure that there is no couch db update 
conflict
+        cy.wait(1000);
         ConnectBtns.storeEditAdapter().click();
 
         cy.dataCy('sp-connect-adapter-success-added', {
diff --git a/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.spec.ts 
b/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.spec.ts
index c30f355474..c3f14b7a29 100644
--- a/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.spec.ts
+++ b/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.spec.ts
@@ -18,7 +18,7 @@
 
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
 import { ConnectBtns } from '../../support/utils/connect/ConnectBtns';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 import { AdapterBuilder } from '../../support/builder/AdapterBuilder';
diff --git a/ui/cypress/tests/connect/persistInDataLake.smoke.spec.ts 
b/ui/cypress/tests/connect/persistInDataLake.smoke.spec.ts
index 39c672b6a7..939bf44312 100644
--- a/ui/cypress/tests/connect/persistInDataLake.smoke.spec.ts
+++ b/ui/cypress/tests/connect/persistInDataLake.smoke.spec.ts
@@ -17,7 +17,7 @@
  */
 
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { FileManagementUtils } from '../../support/utils/FileManagementUtils';
 import { AdapterBuilder } from '../../support/builder/AdapterBuilder';
 import { ConnectBtns } from '../../support/utils/connect/ConnectBtns';
diff --git a/ui/cypress/tests/datalake/configuration.smoke.spec.ts 
b/ui/cypress/tests/datalake/configuration.smoke.spec.ts
index 3b5532e154..1b095ab07e 100644
--- a/ui/cypress/tests/datalake/configuration.smoke.spec.ts
+++ b/ui/cypress/tests/datalake/configuration.smoke.spec.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { DataLakeUtils } from '../../support/utils/datalake/DataLakeUtils';
 
 describe('Test Truncate data in datalake', () => {
diff --git 
a/ui/cypress/tests/experimental/restartStreamPipes/restartStreamPipes1.ts 
b/ui/cypress/tests/experimental/restartStreamPipes/restartStreamPipes1.ts
index 3f098de23a..d8eafe8bc1 100644
--- a/ui/cypress/tests/experimental/restartStreamPipes/restartStreamPipes1.ts
+++ b/ui/cypress/tests/experimental/restartStreamPipes/restartStreamPipes1.ts
@@ -17,7 +17,7 @@
  */
 
 import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../../support/builder/PipelineBuilder';
 import { DashboardUtils } from '../../../support/utils/DashboardUtils';
diff --git a/ui/cypress/tests/experimental/testJvmArchetype/testJvmArchetype.ts 
b/ui/cypress/tests/experimental/testJvmArchetype/testJvmArchetype.ts
index 2a41d84eec..c15490d2e4 100644
--- a/ui/cypress/tests/experimental/testJvmArchetype/testJvmArchetype.ts
+++ b/ui/cypress/tests/experimental/testJvmArchetype/testJvmArchetype.ts
@@ -17,7 +17,7 @@
  */
 
 import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../../support/builder/PipelineBuilder';
 import { DashboardUtils } from '../../../support/utils/DashboardUtils';
diff --git a/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts 
b/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
index 1de708d27f..010f7695f9 100644
--- a/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
+++ b/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
@@ -17,7 +17,7 @@
  */
 
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 
diff --git a/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts 
b/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
index b2e69bd0b4..5de2359906 100644
--- a/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
+++ b/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
@@ -17,7 +17,7 @@
  */
 
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 
diff --git 
a/ui/cypress/tests/pipelineElement/PipelineElementDocumentation.spec.ts 
b/ui/cypress/tests/pipelineElement/PipelineElementDocumentation.spec.ts
index 726ed1c5e2..4387a2e5e6 100644
--- a/ui/cypress/tests/pipelineElement/PipelineElementDocumentation.spec.ts
+++ b/ui/cypress/tests/pipelineElement/PipelineElementDocumentation.spec.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 
 describe('Validate that the markdown documentation for pipeline elements 
works', () => {
     beforeEach('Setup Test', () => {
diff --git 
a/ui/cypress/tests/pipelineElementConfigurationTemplate/pipelineElementConfigurationTemplate.ts
 
b/ui/cypress/tests/pipelineElementConfigurationTemplate/pipelineElementConfigurationTemplate.ts
index 2b9fff9442..16ea5c3543 100644
--- 
a/ui/cypress/tests/pipelineElementConfigurationTemplate/pipelineElementConfigurationTemplate.ts
+++ 
b/ui/cypress/tests/pipelineElementConfigurationTemplate/pipelineElementConfigurationTemplate.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
diff --git a/ui/cypress/tests/userManagement/testGroupManagement.spec.ts 
b/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
index 2f4de9e7bf..03d7159568 100644
--- a/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
+++ b/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
@@ -20,7 +20,7 @@ import { UserBuilder } from 
'../../support/builder/UserBuilder';
 import { UserRole } from '../../../src/app/_enums/user-role.enum';
 import { UserUtils } from '../../support/utils/UserUtils';
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 
diff --git a/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts 
b/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
index a992334de8..94d83418ff 100644
--- a/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
+++ b/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
@@ -20,7 +20,7 @@ import { UserBuilder } from 
'../../support/builder/UserBuilder';
 import { UserRole } from '../../../src/app/_enums/user-role.enum';
 import { UserUtils } from '../../support/utils/UserUtils';
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineUtils } from '../../support/utils/PipelineUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
 
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
index 68f9377e8f..c613d3cda3 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
@@ -42,6 +42,7 @@
                     *ngFor="let item of spNavigationItems"
                     (click)="navigateTo(item)"
                     [active]="activeLink === item.itemId"
+                    [attr.data-cy]="'tab-' + item.itemTitle"
                 >
                     <span>{{ item.itemTitle }}</span>
                 </a>
diff --git 
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
 
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
index f7ff5b8c7b..d4eecdd6a7 100644
--- 
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
+++ 
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
@@ -150,6 +150,7 @@
             optionTitle="Show code"
             optionDescription="Show code to programmatically deploy this 
adapter over the API"
             optionIcon="code"
+            dataCy="show-code-checkbox"
             (optionSelectedEmitter)="showCode = $event"
         >
             @if (showCode) {
diff --git 
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts 
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
index 598dae37ae..459327fd25 100644
--- 
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
+++ 
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
@@ -24,6 +24,7 @@ import {
     CompactPipeline,
     CompactPipelineElement,
     ErrorMessage,
+    Message,
     PipelineOperationStatus,
     PipelineTemplateService,
     PipelineUpdateInfo,
@@ -112,16 +113,22 @@ export class AdapterStartedDialog implements OnInit {
     updateAdapter(): void {
         this.loadingText = `Updating adapter ${this.adapter.name}`;
         this.loading = true;
-        this.adapterService.updateAdapter(this.adapter).subscribe(
-            res => {
-                this.onAdapterReady(
-                    `Adapter ${this.adapter.name} was successfully updated and 
is available in the pipeline editor.`,
-                );
+        this.adapterService.updateAdapter(this.adapter).subscribe({
+            next: status => {
+                if (status.success) {
+                    this.onAdapterReady(
+                        `Adapter ${this.adapter.name} was successfully updated 
and is available in the pipeline editor.`,
+                    );
+                } else {
+                    const errorLogMessage = this.getErrorLogMessage(status);
+
+                    this.onAdapterFailure(errorLogMessage);
+                }
             },
-            error => {
+            error: error => {
                 this.onAdapterFailure(error.error);
             },
-        );
+        });
     }
 
     addAdapter() {
@@ -137,16 +144,8 @@ export class AdapterStartedDialog implements OnInit {
                         this.startAdapter(adapterElementId, true);
                     }
                 } else {
-                    const errorMsg: SpLogMessage = {
-                        cause:
-                            status.notifications.length > 0
-                                ? status.notifications[0].title
-                                : 'Unknown Error',
-                        detail: '',
-                        fullStackTrace: '',
-                        level: 'ERROR',
-                        title: 'Unknown Error',
-                    };
+                    const errorMsg: SpLogMessage =
+                        this.getErrorLogMessage(status);
 
                     this.onAdapterFailure(errorMsg);
                 }
@@ -157,6 +156,20 @@ export class AdapterStartedDialog implements OnInit {
         );
     }
 
+    private getErrorLogMessage(status: Message): SpLogMessage {
+        const notification = status.notifications[0] || {
+            title: 'Unknown Error',
+            description: '',
+        };
+        return {
+            cause: notification.title,
+            detail: '',
+            fullStackTrace: notification.description,
+            level: 'ERROR',
+            title: 'Unknown Error',
+        };
+    }
+
     startAdapter(adapterElementId: string, showPreview = false) {
         const successMessage =
             'Your new data stream is now available in the pipeline editor.';
diff --git 
a/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html
 
b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html
index 083d9291c7..a6590ce049 100644
--- 
a/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html
+++ 
b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html
@@ -22,6 +22,7 @@
             [innerHTML]="configuration | yamlpretty"
             class="preview-text"
             [ngStyle]="{ maxHeight: maxHeight }"
+            data-cy="yaml-configuration"
         ></pre>
     </mat-tab>
     <mat-tab label="JSON">
@@ -29,6 +30,7 @@
             [innerHTML]="configuration | jsonpretty"
             class="preview-text"
             [ngStyle]="{ maxHeight: maxHeight }"
+            data-cy="json-configuration"
         ></pre>
     </mat-tab>
 </mat-tab-group>
diff --git 
a/ui/src/app/core-ui/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
 
b/ui/src/app/core-ui/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
index ffaf3bd5b2..ceb6851ab4 100644
--- 
a/ui/src/app/core-ui/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
+++ 
b/ui/src/app/core-ui/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
@@ -57,7 +57,12 @@
             <th mat-header-cell *matHeaderCellDef><strong>Value</strong></th>
             <td mat-cell *matCellDef="let element" style="width: 200px">
                 @if (element.value === undefined) {
-                    <div class="value no-data">no data</div>
+                    <div
+                        data-cy="live-preview-table-no-data"
+                        class="value no-data"
+                    >
+                        no data
+                    </div>
                 } @else {
                     <ng-container *ngIf="element.isImage">
                         <img
@@ -75,7 +80,9 @@
                     </ng-container>
                     <ng-container *ngIf="element.hasNoDomainProperty">
                         <div
-                            data-cy="live-preview-table-value"
+                            [attr.data-cy]="
+                                'live-preview-value-' + element.runtimeName
+                            "
                             class="value"
                             [class.value-changed]="element.valueChanged"
                         >

Reply via email to