Sfoglia il codice sorgente

[e2e] Implement Qase.io integration (#2233)

* qase.io integration
moved all helpers/util to main/java

* fix for locator (message/content)

* fix for locator (message/content) v2

* refactoring due to review

* refactoring, added verification by @CaseId

* small fix with NullPointer

* TEST FAILED RUN

* TEST FAILED RUN2

* TEST FAILED RUN3

* removed token, set correct @CaseId

* added status SKIPED for manual tests or not automated
changed getting token .getenv

* fix for token

* changed cases limit to 100

* fix for getting token

* refactoring due review

* changed name of variable

Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
kshpilchyna 2 anni fa
parent
commit
cfcadd122c
36 ha cambiato i file con 524 aggiunte e 89 eliminazioni
  1. 18 13
      kafka-ui-e2e-checks/pom.xml
  2. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/FileUtils.java
  3. 148 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/QaseExtension.java
  4. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/WaitUtils.java
  5. 1 4
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/ApiHelper.java
  6. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/Helpers.java
  7. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/TestConfiguration.java
  8. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/MainPage.java
  9. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/Pages.java
  10. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ProduceMessagePage.java
  11. 1 1
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorCreateView.java
  12. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorUpdateView.java
  13. 4 4
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorsList.java
  14. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorsView.java
  15. 4 4
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaCreateView.java
  16. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaEditView.java
  17. 1 1
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaRegistryList.java
  18. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaView.java
  19. 18 13
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicCreateEditSettingsView.java
  20. 5 5
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicView.java
  21. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicsList.java
  22. 1 1
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/screenshots/NoReferenceScreenshotFoundException.java
  23. 14 15
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/screenshots/Screenshooter.java
  24. 0 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/BrowserUtils.java
  25. 1 1
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/CamelCaseToSpacedDisplayNameGenerator.java
  26. 23 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/MethodNameUtils.java
  27. 5 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/Status.java
  28. 164 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/TestCaseGenerator.java
  29. 12 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/annotation/AutomationStatus.java
  30. 10 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/annotation/Suite.java
  31. 1 0
      kafka-ui-e2e-checks/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener
  32. 5 0
      kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/SmokeTests.java
  33. 13 6
      kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/base/BaseTest.java
  34. 18 3
      kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/ConnectorsTests.java
  35. 30 2
      kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/SchemasTests.java
  36. 19 8
      kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/TopicTests.java

+ 18 - 13
kafka-ui-e2e-checks/pom.xml

@@ -14,25 +14,26 @@
         <kafka-ui-contract>${project.version}</kafka-ui-contract>
         <junit.version>5.8.2</junit.version>
         <aspectj.version>1.9.8</aspectj.version>
-        <allure.version>2.17.2</allure.version>
-        <json-smart.version>1.3.3</json-smart.version>
-        <testcontainers.version>1.16.3</testcontainers.version>
-        <selenide.version>6.3.0</selenide.version>
-        <assertj.version>3.17.1</assertj.version>
-        <google.auto-service.version>1.0-rc7</google.auto-service.version>
+        <allure.version>2.18.1</allure.version>
+        <json-smart.version>2.4.8</json-smart.version>
+        <testcontainers.version>1.17.2</testcontainers.version>
+        <selenide.version>6.6.3</selenide.version>
+        <assertj.version>3.23.1</assertj.version>
+        <google.auto-service.version>1.0.1</google.auto-service.version>
         <hamcrest.version>2.2</hamcrest.version>
-        <slf4j.version>1.7.32</slf4j.version>
-        <testcontainers.junit-jupiter.version>1.16.3</testcontainers.junit-jupiter.version>
-        <allure.java-commons.version>2.17.2</allure.java-commons.version>
-        <dotenv.version>2.2.0</dotenv.version>
+        <slf4j.version>1.7.36</slf4j.version>
+        <testcontainers.junit-jupiter.version>1.17.2</testcontainers.junit-jupiter.version>
+        <allure.java-commons.version>2.18.1</allure.java-commons.version>
+        <dotenv.version>2.2.4</dotenv.version>
         <junit.platform-launcher.version>1.8.2</junit.platform-launcher.version>
         <allure.maven-plugin.version>2.6</allure.maven-plugin.version>
         <ashot.version>1.5.4</ashot.version>
-        <allure.screendiff-plugin.version>2.17.2</allure.screendiff-plugin.version>
+        <allure.screendiff-plugin.version>2.18.1</allure.screendiff-plugin.version>
         <maven.surefire-plugin.version>2.22.2</maven.surefire-plugin.version>
         <allure-maven.version>2.10.0</allure-maven.version>
         <kafka.version>3.0.0</kafka.version>
         <netty.version>4.1.77.Final</netty.version>
+        <qase.io.version>2.1.3</qase.io.version>
     </properties>
 
     <dependencies>
@@ -207,7 +208,7 @@
         <dependency>
             <groupId>org.junit.platform</groupId>
             <artifactId>junit-platform-launcher</artifactId>
-            <version>${junit.platform-launcher.version}</version>
+           <version>${junit.platform-launcher.version}</version>
         </dependency>
         <dependency>
             <groupId>ru.yandex.qatools.allure</groupId>
@@ -234,7 +235,6 @@
             <groupId>com.provectus</groupId>
             <artifactId>kafka-ui-contract</artifactId>
             <version>${kafka-ui-contract}</version>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.testcontainers</groupId>
@@ -242,6 +242,11 @@
             <version>${testcontainers.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>io.qase</groupId>
+            <artifactId>qase-api</artifactId>
+            <version>${qase.io.version}</version>
+        </dependency>
     </dependencies>
 
     <profiles>

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/extensions/FileUtils.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/FileUtils.java


+ 148 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/QaseExtension.java

@@ -0,0 +1,148 @@
+package com.provectus.kafka.ui.extensions;
+
+import com.provectus.kafka.ui.utils.qaseIO.TestCaseGenerator;
+import io.qase.api.QaseClient;
+import io.qase.api.StepStorage;
+import io.qase.api.exceptions.QaseException;
+import io.qase.client.ApiClient;
+import io.qase.client.api.ResultsApi;
+import io.qase.client.model.ResultCreate;
+import io.qase.client.model.ResultCreate.StatusEnum;
+import io.qase.client.model.ResultCreateSteps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.engine.TestSource;
+import org.junit.platform.engine.support.descriptor.MethodSource;
+import org.junit.platform.launcher.TestExecutionListener;
+import org.junit.platform.launcher.TestIdentifier;
+
+import javax.annotation.Nullable;
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.time.Duration;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static io.qase.api.QaseClient.getConfig;
+import static io.qase.api.utils.IntegrationUtils.getCaseId;
+import static io.qase.api.utils.IntegrationUtils.getStacktrace;
+import static org.junit.platform.engine.TestExecutionResult.Status.SUCCESSFUL;
+
+@Slf4j
+public class QaseExtension implements TestExecutionListener {
+
+    private final ApiClient apiClient = QaseClient.getApiClient();
+    private final ResultsApi resultsApi = new ResultsApi(apiClient);
+    private final Map<TestIdentifier, Long> testStartTimes = new ConcurrentHashMap<>();
+    private static final String QASE_PROJECT = "KAFKAUI";
+    private static final String QASE_ENABLE = "true";
+
+
+    static {
+        String qaseApiToken = System.getProperty("QASEIO_API_TOKEN");
+
+        if (qaseApiToken == null || StringUtils.isEmpty(qaseApiToken)) {
+            throw new RuntimeException("QaseIO API token should be present");
+        }
+
+        if ("true".equalsIgnoreCase(System.getProperty("QASEIO_CREATE_TESTRUN"))) {
+            System.setProperty("QASE_RUN_NAME", "Automation run " +
+                    new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date()));
+        }
+        System.setProperty("QASE_ENABLE", QASE_ENABLE);
+        System.setProperty("QASE_PROJECT_CODE", QASE_PROJECT);
+        System.setProperty("QASE_API_TOKEN", qaseApiToken);
+        System.setProperty("QASE_USE_BULK", "false");
+    }
+
+
+    @Override
+    public void executionStarted(TestIdentifier testIdentifier) {
+        if (QaseClient.isEnabled() && testIdentifier.isTest()) {
+            testStartTimes.put(testIdentifier, System.currentTimeMillis());
+        }
+    }
+
+    @Override
+    public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
+        if (!testIdentifier.isTest() || !QaseClient.isEnabled()
+                || !testStartTimes.containsKey(testIdentifier)) {
+            return;
+        }
+        TestSource testSource = testIdentifier.getSource().orElse(null);
+        Method testMethod = null;
+        if (testSource instanceof MethodSource) {
+            testMethod = getMethod((MethodSource) testSource);
+        }
+        TestCaseGenerator.createTestCaseIfNotExists(testMethod);
+        Duration duration = Duration.ofMillis(System.currentTimeMillis() - this.testStartTimes.remove(testIdentifier));
+        sendResults(testExecutionResult, duration, testMethod);
+    }
+
+    private void sendResults(TestExecutionResult testExecutionResult, Duration timeSpent, Method testMethod) {
+        if (testMethod != null) {
+            ResultCreate resultCreate = getResultItem(testExecutionResult, timeSpent, testMethod);
+            try {
+                resultsApi.createResult(getConfig().projectCode(),
+                        getConfig().runId(),
+                        resultCreate);
+                log.info("Method = " + testMethod.getName() + ": Result added to test run with Id = {}", getConfig().runId());
+            } catch (QaseException e) {
+                log.error("Method = " + testMethod.getName() + ": Result not added to test Run because there is no @CaseId annotation or case not found", e);
+            }
+        }
+    }
+
+    private ResultCreate getResultItem(TestExecutionResult testExecutionResult, Duration timeSpent, Method testMethod) {
+        String testCaseTitle = TestCaseGenerator.generateTestCaseTitle(testMethod);
+        TestCaseGenerator.createTestCaseIfNotExists(testMethod);
+        Long caseId = getCaseId(testMethod);
+        Map<Long, String> cases = TestCaseGenerator.getTestCasesTitleAndId();
+        StatusEnum status = StatusEnum.SKIPPED;
+
+        if (caseId == null || !TestCaseGenerator.isCaseIdPresentInQaseIo(testMethod)) {
+            for (Map.Entry<Long, String> map : cases.entrySet()) {
+                if (map.getValue().matches(testCaseTitle)) {
+                    caseId = map.getKey();
+                    log.info("There is no annotation @CaseId but there is test case with title '" + testCaseTitle + "' and with id = " + caseId
+                            + " that will be added to test Run");
+                }
+            }
+        }
+
+        if (TestCaseGenerator.getAutomationStatus(testMethod) == 2) {
+            status = testExecutionResult.getStatus() == SUCCESSFUL ? StatusEnum.PASSED : StatusEnum.FAILED;
+        }
+
+        String comment = testExecutionResult.getThrowable()
+                .flatMap(throwable -> Optional.of(throwable.toString())).orElse(null);
+        Boolean isDefect = testExecutionResult.getThrowable()
+                .flatMap(throwable -> Optional.of(throwable instanceof AssertionError))
+                .orElse(false);
+        String stacktrace = testExecutionResult.getThrowable()
+                .flatMap(throwable -> Optional.of(getStacktrace(throwable))).orElse(null);
+        LinkedList<ResultCreateSteps> steps = StepStorage.getSteps();
+        return new ResultCreate()
+                .caseId(caseId)
+                .status(status)
+                .timeMs(timeSpent.toMillis())
+                .comment(comment)
+                .stacktrace(stacktrace)
+                .steps(steps.isEmpty() ? null : steps)
+                .defect(isDefect);
+    }
+
+    @Nullable
+    private Method getMethod(MethodSource testSource) {
+        try {
+            Class<?> testClass = Class.forName(testSource.getClassName());
+            return Arrays.stream(testClass.getDeclaredMethods())
+                    .filter(method -> MethodSource.from(method).equals(testSource))
+                    .findFirst().orElse(null);
+        } catch (ClassNotFoundException e) {
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+}

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/extensions/WaitUtils.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/extensions/WaitUtils.java


+ 1 - 4
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/helpers/ApiHelper.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/ApiHelper.java

@@ -7,7 +7,6 @@ import com.provectus.kafka.ui.api.api.MessagesApi;
 import com.provectus.kafka.ui.api.api.SchemasApi;
 import com.provectus.kafka.ui.api.api.TopicsApi;
 import com.provectus.kafka.ui.api.model.*;
-import com.provectus.kafka.ui.base.TestConfiguration;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
@@ -23,7 +22,6 @@ public class ApiHelper {
 
     int partitions = 1;
     int replicationFactor = 1;
-    String newTopic = "new-topic";
     String baseURL = TestConfiguration.BASE_API_URL;
 
 
@@ -53,10 +51,9 @@ public class ApiHelper {
         topic.setName(topicName);
         topic.setPartitions(partitions);
         topic.setReplicationFactor(replicationFactor);
-        deleteTopic(clusterName, topicName);
-        sleep(2000);
         try {
             topicApi().createTopic(clusterName, topic).block();
+            sleep(2000);
         } catch (WebClientResponseException ex) {
             ex.printStackTrace();
         }

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/helpers/Helpers.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/Helpers.java


+ 2 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/base/TestConfiguration.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/helpers/TestConfiguration.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.base;
+package com.provectus.kafka.ui.helpers;
 
 public class TestConfiguration {
   public static boolean CLEAR_REPORTS_DIR =
@@ -18,6 +18,6 @@ public class TestConfiguration {
   public static String BROWSER_SIZE = System.getProperty("BROWSER_SIZE", "1920x1080");
   public static Boolean ENABLE_VNC = Boolean.parseBoolean(System.getProperty("ENABLE_VNC", "true"));
   public static String IMAGE_NAME = System.getProperty("SELENIUM_DOCKER_IMAGE", "selenium/standalone-chrome");
-  public static String IMAGE_TAG = System.getProperty("SELENIUM_IMAGE_TAG", "102.0");
+  public static String IMAGE_TAG = System.getProperty("SELENIUM_IMAGE_TAG", "103.0");
 
 }

+ 2 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/MainPage.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/MainPage.java

@@ -3,7 +3,7 @@ package com.provectus.kafka.ui.pages;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.Selenide;
 import com.codeborne.selenide.SelenideElement;
-import com.provectus.kafka.ui.base.TestConfiguration;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.extensions.WaitUtils;
 import com.provectus.kafka.ui.pages.topic.TopicsList;
 import io.qameta.allure.Step;
@@ -48,7 +48,7 @@ public class MainPage {
     CONSUMERS("Consumers"),
     SCHEMA_REGISTRY("Schema Registry");
 
-    String value;
+    final String value;
 
     SideMenuOptions(String value) {
       this.value = value;

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/Pages.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/Pages.java


+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/ProduceMessagePage.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ProduceMessagePage.java


+ 1 - 1
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/connector/ConnectorCreateView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorCreateView.java

@@ -2,8 +2,8 @@ package com.provectus.kafka.ui.pages.connector;
 
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
-import com.provectus.kafka.ui.extensions.WaitUtils;
 import com.provectus.kafka.ui.utils.BrowserUtils;
+import com.provectus.kafka.ui.extensions.WaitUtils;
 import io.qameta.allure.Step;
 import lombok.experimental.ExtensionMethod;
 import org.openqa.selenium.By;

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/connector/ConnectorUpdateView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorUpdateView.java


+ 4 - 4
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/connector/ConnectorsList.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorsList.java

@@ -2,9 +2,9 @@ package com.provectus.kafka.ui.pages.connector;
 
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.Selenide;
-import com.provectus.kafka.ui.base.TestConfiguration;
-import com.provectus.kafka.ui.extensions.WaitUtils;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.utils.BrowserUtils;
+import com.provectus.kafka.ui.extensions.WaitUtils;
 import io.qameta.allure.Step;
 import lombok.SneakyThrows;
 import lombok.experimental.ExtensionMethod;
@@ -56,8 +56,8 @@ public class ConnectorsList {
     }
 
     public ConnectorsList connectorIsUpdatedInList(String connectorName, String topicName) {
-        $(By.xpath("//a[text() = '%s']".formatted(connectorName))).shouldBe(Condition.visible);
-        By.xpath("//a[text() = '%s']".formatted(topicName)).refreshUntil(Condition.visible);
+        $(By.xpath(String.format("//a[text() = '%s']", connectorName))).shouldBe(Condition.visible);
+        By.xpath(String.format("//a[text() = '%s']", topicName)).refreshUntil(Condition.visible);
         return this;
     }
 }

+ 2 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/connector/ConnectorsView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connector/ConnectorsView.java

@@ -2,7 +2,7 @@ package com.provectus.kafka.ui.pages.connector;
 
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.Selenide;
-import com.provectus.kafka.ui.base.TestConfiguration;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.extensions.WaitUtils;
 import com.provectus.kafka.ui.utils.BrowserUtils;
 import io.qameta.allure.Step;
@@ -18,7 +18,7 @@ public class ConnectorsView {
 
     @Step
     public ConnectorsView goTo(String cluster, String connector) {
-        Selenide.open(TestConfiguration.BASE_WEB_URL + path.format(cluster, connector));
+        Selenide.open(String.format(TestConfiguration.BASE_WEB_URL + path, cluster, connector));
         return this;
     }
 

+ 4 - 4
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/schema/SchemaCreateView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaCreateView.java

@@ -9,9 +9,9 @@ import static com.codeborne.selenide.Selenide.$x;
 
 public class SchemaCreateView {
 
-    private SelenideElement subjectName = $(By.xpath("//input[@name='subject']"));
-    private SelenideElement schemaField = $(By.xpath("//textarea[@name='schema']"));
-    private SelenideElement submitSchemaButton = $(By.xpath("//button[@type='submit']"));
+    private final SelenideElement subjectName = $(By.xpath("//input[@name='subject']"));
+    private final SelenideElement schemaField = $(By.xpath("//textarea[@name='schema']"));
+    private final SelenideElement submitSchemaButton = $(By.xpath("//button[@type='submit']"));
 
     public SchemaCreateView selectSchemaTypeFromDropdown(SchemaType schemaType) {
         $("ul[role='listbox']").click();
@@ -39,7 +39,7 @@ public class SchemaCreateView {
         JSON("JSON"),
         PROTOBUF("PROTOBUF");
 
-        String value;
+        final String value;
 
         SchemaType(String value) {
             this.value = value;

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/schema/SchemaEditView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaEditView.java


+ 1 - 1
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/schema/SchemaRegistryList.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaRegistryList.java

@@ -11,7 +11,7 @@ import static com.codeborne.selenide.Selenide.*;
 
 public class SchemaRegistryList {
 
-    private SelenideElement schemaButton = $(By.xpath("//*[contains(text(),'Create Schema')]"));
+    private final SelenideElement schemaButton = $(By.xpath("//*[contains(text(),'Create Schema')]"));
 
     public SchemaCreateView clickCreateSchema() {
         BrowserUtils.javaExecutorClick(schemaButton);

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/schema/SchemaView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schema/SchemaView.java


+ 18 - 13
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/topic/TopicCreateEditSettingsView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicCreateEditSettingsView.java

@@ -1,13 +1,14 @@
 package com.provectus.kafka.ui.pages.topic;
 
-import static com.codeborne.selenide.Selenide.$;
-import static com.codeborne.selenide.Selenide.$$;
-import static com.codeborne.selenide.Selenide.$x;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import com.codeborne.selenide.*;
-import com.provectus.kafka.ui.utils.BrowserUtils;
+import com.codeborne.selenide.ClickOptions;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.SelenideElement;
 import org.openqa.selenium.By;
+import com.provectus.kafka.ui.utils.BrowserUtils;
+
+import static com.codeborne.selenide.Selenide.*;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class TopicCreateEditSettingsView {
 
@@ -81,7 +82,7 @@ public class TopicCreateEditSettingsView {
     }
 
     public TopicView sendData() {
-        BrowserUtils.javaExecutorClick($(".ezTgzA.sc-bYEvvW"));
+        BrowserUtils.javaExecutorClick($x("//button[@type='submit']"));
         return new TopicView();
     }
 
@@ -101,8 +102,10 @@ public class TopicCreateEditSettingsView {
             customParametersElements = $$("ul[role=listbox][name^=customParams][name$=name]");
             kafkaUISelectElement = new KafkaUISelectElement(customParametersElements.last());
         }
-        kafkaUISelectElement.selectByVisibleText(customParameterName);
-        $("input[name=\"customParams.%d.value\"]".formatted(customParametersElements.size() - 1))
+        if (kafkaUISelectElement != null) {
+            kafkaUISelectElement.selectByVisibleText(customParameterName);
+        }
+        $(String.format("input[name=\"customParams.%d.value\"]", customParametersElements.size() - 1))
                 .setValue(customParameterValue);
         return this;
     }
@@ -112,8 +115,10 @@ public class TopicCreateEditSettingsView {
         SelenideElement selenideElement = $$("ul[role=listbox][name^=customParams][name$=name]")
                 .find(Condition.exactText(customParameterName));
         String name = selenideElement.getAttribute("name");
-        name = name.substring(0, name.lastIndexOf("."));
-        $("input[name^=%s]".formatted(name)).setValue(customParameterValue);
+        if (name != null) {
+            name = name.substring(0, name.lastIndexOf("."));
+        }
+        $(String.format("input[name^=%s]", name)).setValue(customParameterValue);
         return this;
     }
 
@@ -154,7 +159,7 @@ public class TopicCreateEditSettingsView {
 
     private static class KafkaUISelectElement {
 
-        private SelenideElement selectElement;
+        private final SelenideElement selectElement;
 
         public KafkaUISelectElement(String selectElementName) {
             this.selectElement = $("ul[role=listbox][name=" + selectElementName + "]");

+ 5 - 5
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/topic/TopicView.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicView.java

@@ -3,7 +3,7 @@ package com.provectus.kafka.ui.pages.topic;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.Selenide;
 import com.codeborne.selenide.SelenideElement;
-import com.provectus.kafka.ui.base.TestConfiguration;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.extensions.WaitUtils;
 import com.provectus.kafka.ui.pages.ProduceMessagePage;
 import com.provectus.kafka.ui.utils.BrowserUtils;
@@ -57,7 +57,7 @@ public class TopicView {
 
     @SneakyThrows
     public ProduceMessagePage clickOnButton(String buttonName) {
-        BrowserUtils.javaExecutorClick($(By.xpath("//div//button[text()='%s']".formatted(buttonName))));
+        BrowserUtils.javaExecutorClick($(By.xpath(String.format("//div//button[text()='%s']", buttonName))));
         return new ProduceMessagePage();
     }
 
@@ -66,13 +66,13 @@ public class TopicView {
     }
 
     public boolean isContentMessageVisible(String contentMessage) {
-        return contentMessage.equals($(".bPpPJI.sc-gkdBiK").getText());
+        return contentMessage.matches($x("//html//div[@id='root']/div/main//table//p").getText().trim());
     }
 
     private enum DotMenuHeaderItems {
         EDIT_SETTINGS("Edit settings"), CLEAR_MESSAGES("Clear messages"), REMOVE_TOPIC("Remove topic");
 
-        private String value;
+        private final String value;
 
         DotMenuHeaderItems(String value) {
             this.value = value;
@@ -91,7 +91,7 @@ public class TopicView {
     public enum TopicMenu {
         OVERVIEW("Overview"), MESSAGES("Messages"), CONSUMERS("Consumers"), SETTINGS("Settings");
 
-        private String value;
+        private final String value;
 
         TopicMenu(String value) {
             this.value = value;

+ 2 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/pages/topic/TopicsList.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicsList.java

@@ -3,7 +3,7 @@ package com.provectus.kafka.ui.pages.topic;
 import com.codeborne.selenide.CollectionCondition;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.Selenide;
-import com.provectus.kafka.ui.base.TestConfiguration;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.extensions.WaitUtils;
 import com.provectus.kafka.ui.utils.BrowserUtils;
 import io.qameta.allure.Step;
@@ -33,7 +33,7 @@ public class TopicsList {
 
     @Step
     public TopicCreateEditSettingsView pressCreateNewTopic(){
-        BrowserUtils.javaExecutorClick($(".qEXNn.sc-bYEvvW"));
+        BrowserUtils.javaExecutorClick($x("//button[normalize-space(text()) ='Add a Topic']"));
         return new TopicCreateEditSettingsView();
     }
 

+ 1 - 1
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/screenshots/NoReferenceScreenshotFoundException.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/screenshots/NoReferenceScreenshotFoundException.java

@@ -2,6 +2,6 @@ package com.provectus.kafka.ui.screenshots;
 
 public class NoReferenceScreenshotFoundException extends Throwable {
     public NoReferenceScreenshotFoundException(String name) {
-        super(("no reference screenshot found for %s".formatted(name)));
+        super("no reference screenshot found for " + name);
     }
 }

+ 14 - 15
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/screenshots/Screenshooter.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/screenshots/Screenshooter.java

@@ -20,25 +20,24 @@ import java.nio.file.FileSystems;
 import java.util.List;
 
 import static com.codeborne.selenide.WebDriverRunner.getWebDriver;
-import static org.junit.jupiter.api.Assertions.fail;
 
 public class Screenshooter {
 
   public static  Logger log = LoggerFactory.getLogger(Screenshooter.class);
 
-  private static int PIXELS_THRESHOLD =
+  private static final int PIXELS_THRESHOLD =
       Integer.parseInt(System.getProperty("PIXELS_THRESHOLD", "200"));
-  private static String SCREENSHOTS_FOLDER =
-      System.getProperty("SCREENSHOTS_FOLDER", "screenshots/");
-  private static String DIFF_SCREENSHOTS_FOLDER =
+  private static final String SCREENSHOTS_FOLDER =
+      System.getProperty("SCREENSHOTS_FOLDER", "com/provectus/kafka/ui/screenshots/");
+  private static final String DIFF_SCREENSHOTS_FOLDER =
       System.getProperty("DIFF_SCREENSHOTS_FOLDER", "build/__diff__/");
-  private static String ACTUAL_SCREENSHOTS_FOLDER =
+  private static final String ACTUAL_SCREENSHOTS_FOLDER =
       System.getProperty("ACTUAL_SCREENSHOTS_FOLDER", "build/__actual__/");
-  private static boolean SHOULD_SAVE_SCREENSHOTS_IF_NOT_EXIST =
+  private static final boolean SHOULD_SAVE_SCREENSHOTS_IF_NOT_EXIST =
       Boolean.parseBoolean(System.getProperty("SHOULD_SAVE_SCREENSHOTS_IF_NOT_EXIST", "true"));
-  private static boolean TURN_OFF_SCREENSHOTS =
+  private static final boolean TURN_OFF_SCREENSHOTS =
       Boolean.parseBoolean(System.getProperty("TURN_OFF_SCREENSHOTS", "false"));
-  private static boolean USE_LOCAL_BROWSER =
+  private static final boolean USE_LOCAL_BROWSER =
           Boolean.parseBoolean(System.getProperty("USE_LOCAL_BROWSER", "false"));
 
   private File newFile(String name) {
@@ -61,8 +60,8 @@ public class Screenshooter {
   @SneakyThrows
   public void compareScreenshots(String name, boolean shouldUpdateScreenshotIfDiffer) {
     if (TURN_OFF_SCREENSHOTS || USE_LOCAL_BROWSER) {
-      log.warn("compareScreenshots turned off due TURN_OFF_SCREENSHOTS || USE_LOCAL_BROWSER: %b || %b"
-              .formatted(TURN_OFF_SCREENSHOTS,USE_LOCAL_BROWSER));
+      log.warn(String.format("compareScreenshots turned off due TURN_OFF_SCREENSHOTS || USE_LOCAL_BROWSER: %b || %b"
+              , TURN_OFF_SCREENSHOTS,USE_LOCAL_BROWSER));
       return;
     }
     if (!doesScreenshotExist(name)) {
@@ -82,7 +81,7 @@ public class Screenshooter {
         new AShot().coordsProvider(new WebDriverCoordsProvider()).takeScreenshot(getWebDriver());
     File  file=  newFile(SCREENSHOTS_FOLDER + name + ".png");
     ImageIO.write(actual.getImage(), "png", file);
-    log.debug("created screenshot: %s \n at $s".formatted(name,file.getAbsolutePath()));
+    log.debug(String.format("created screenshot: %s \n at %s", name, file.getAbsolutePath()));
   }
 
   private static boolean doesScreenshotExist(String name) {
@@ -120,9 +119,9 @@ public class Screenshooter {
     } else {
       Assertions.assertTrue(
           PIXELS_THRESHOLD >= diff.getDiffSize(),
-              ("Amount of differing pixels should be less or equals than %s, actual %s\n"+
-                  "diff file: %s")
-              .formatted(PIXELS_THRESHOLD, diff.getDiffSize(), FileSystems.getDefault().getPath(fullPathNameDiff).normalize().toAbsolutePath().toString()));
+              String.format("Amount of differing pixels should be less or equals than %s, actual %s\n"+
+                  "diff file: %s",
+              PIXELS_THRESHOLD, diff.getDiffSize(), FileSystems.getDefault().getPath(fullPathNameDiff).normalize().toAbsolutePath()));
     }
   }
 

+ 0 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/utils/BrowserUtils.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/BrowserUtils.java


+ 1 - 1
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/base/CamelCaseToSpacedDisplayNameGenerator.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/CamelCaseToSpacedDisplayNameGenerator.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.base;
+package com.provectus.kafka.ui.utils;
 
 import org.junit.jupiter.api.DisplayNameGenerator;
 import org.junit.platform.commons.util.ClassUtils;

+ 23 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/MethodNameUtils.java

@@ -0,0 +1,23 @@
+package com.provectus.kafka.ui.utils.qaseIO;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class MethodNameUtils {
+
+    public static String formatTestCaseTitle(String testMethodName) {
+        String[] split = StringUtils.splitByCharacterTypeCamelCase(testMethodName);
+
+        String[] name = Arrays.stream(split).map(String::toLowerCase).toArray(String[]::new);
+
+        String[] subarray = ArrayUtils.subarray(name, 1, name.length);
+
+        ArrayList<String> stringList = new ArrayList<>(Arrays.asList(subarray));
+        stringList.add(0, StringUtils.capitalize(name[0]));
+
+        return StringUtils.join(stringList, " ");
+    }
+}

+ 5 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/Status.java

@@ -0,0 +1,5 @@
+package com.provectus.kafka.ui.utils.qaseIO;
+
+public enum Status {
+    AUTOMATED, TO_BE_AUTOMATED, MANUAL;
+}

+ 164 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/TestCaseGenerator.java

@@ -0,0 +1,164 @@
+package com.provectus.kafka.ui.utils.qaseIO;
+
+import com.provectus.kafka.ui.utils.qaseIO.annotation.AutomationStatus;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.Suite;
+import io.qase.api.QaseClient;
+import io.qase.api.annotation.CaseId;
+import io.qase.client.ApiClient;
+import io.qase.client.api.CasesApi;
+import io.qase.client.model.*;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Assert;
+import org.junit.platform.engine.support.descriptor.MethodSource;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import static io.qase.api.QaseClient.getConfig;
+
+@Slf4j
+public class TestCaseGenerator {
+
+    public static boolean FAILED = false;
+    private static final ApiClient apiClient = QaseClient.getApiClient();
+    private static final CasesApi casesApi = new CasesApi(apiClient);
+
+    @SneakyThrows
+    public static void createTestCaseIfNotExists(Method testMethod) {
+        TestCaseCreate caseCreate = new TestCaseCreate();
+        String testCaseTitle = generateTestCaseTitle(testMethod);
+        if (!isMethodAnnotatedWithCaseId(testMethod) || !TestCaseGenerator.isCaseIdPresentInQaseIo(testMethod)) {
+            if (!isCaseTitleExistInQaseIo(testMethod)) {
+                caseCreate.setTitle(testCaseTitle);
+                caseCreate.setAutomation(getAutomationStatus(testMethod));
+                if (isMethodAnnotatedWithSuite(testMethod)) {
+                    long suiteId = testMethod.getAnnotation(Suite.class).suiteId();
+                    caseCreate.suiteId(suiteId);
+                }
+                Long caseId = Objects.requireNonNull(casesApi.createCase(getConfig().projectCode(), caseCreate).getResult()).getId();
+                log.info("New test case = '" + testCaseTitle + "' created with id " + caseId);
+            }
+        }
+    }
+
+    @SneakyThrows
+    public static HashMap<Long, String> getTestCasesTitleAndId() {
+        HashMap<Long, String> map = new HashMap<>();
+        boolean getCases = true;
+        int offSet = 0;
+        while (getCases) {
+            getCases = false;
+            TestCaseListResponse response =
+                    casesApi.getCases(getConfig().projectCode(), new Filters().status(Filters.SERIALIZED_NAME_STATUS), 100, offSet);
+            TestCaseListResponseAllOfResult result = response.getResult();
+            Assert.assertNotNull(result);
+            List<TestCase> entities = result.getEntities();
+            Assert.assertNotNull(entities);
+            if (entities.size() > 0) {
+                for (TestCase test : entities) {
+                    map.put(test.getId(), test.getTitle());
+                }
+                offSet = offSet + 100;
+                getCases = true;
+            }
+        }
+        return map;
+    }
+
+    public static boolean isCaseIdPresentInQaseIo(Method testMethod) {
+        if (!testMethod.isAnnotationPresent(CaseId.class)) {
+            return false;
+        }
+        long caseId = testMethod.getAnnotation(CaseId.class).value();
+        HashMap<Long, String> cases = getTestCasesTitleAndId();
+        String title;
+        if (!cases.containsKey(caseId)) {
+            FAILED = true;
+            log.error("The method " + testMethod.getName() + " has wrong @CaseId =" + caseId + " that does not exist in Qase.io. " +
+                    "Please put correct @CaseId");
+            return false;
+        } else {
+            for (Map.Entry<Long, String> map : cases.entrySet()) {
+                if (map.getKey().equals(caseId)) {
+                    title = map.getValue();
+                    if (!title.matches(generateTestCaseTitle(testMethod))) {
+                        log.error("This CaseId =" + caseId + " belong to test with title = " + title);
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private static boolean isCaseTitleExistInQaseIo(Method testMethod) {
+        HashMap<Long, String> cases = getTestCasesTitleAndId();
+        String title = generateTestCaseTitle(testMethod);
+        if (cases.containsValue(title)) {
+            for (Map.Entry<Long, String> map : cases.entrySet()) {
+                if (map.getValue().matches(title)) {
+                    long caseId = map.getKey();
+                    log.info("Test case with title '" + title + "' and id " + caseId + " exist in Qase.io. Verify that annotation @CaseId is correct");
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static int getAutomationStatus(Method testMethod) {
+        if (testMethod.isAnnotationPresent(AutomationStatus.class)) {
+            if (testMethod.getAnnotation(AutomationStatus.class).status().equals(Status.TO_BE_AUTOMATED))
+                return 1;
+            else if (testMethod.getAnnotation(AutomationStatus.class).status().equals(Status.MANUAL))
+                return 0;
+        }
+        return 2;
+    }
+
+    private static boolean isMethodAnnotatedWithCaseId(Method testMethod) {
+        if (!testMethod.isAnnotationPresent(CaseId.class)) {
+            FAILED = true;
+            log.error("You must put annotation @CaseId. The method " + testMethod.getName() + " is NOT annotated with @CaseId.");
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean isMethodAnnotatedWithSuite(Method testMethod) {
+        if (!testMethod.isAnnotationPresent(Suite.class)) {
+            log.info("The method " + testMethod.getName() + " is not annotated with @Suite and new test case will be added without suite");
+            return false;
+        }
+        log.trace("The method is annotated with @Suite with id " + testMethod.getAnnotation(Suite.class).suiteId());
+        return true;
+    }
+
+    private static boolean isMethodAnnotatedWithAutomationStatus(Method testMethod) {
+        if (!testMethod.isAnnotationPresent(AutomationStatus.class)) {
+            log.error("The method " + testMethod.getName() + " is NOT annotated with @AutomationStatus.");
+            return false;
+        }
+        return true;
+    }
+
+    public static String generateTestCaseTitle(Method testMethod) {
+        return getClassName(MethodSource.from(testMethod)) + "." + testMethod.getName() + " : " +
+                MethodNameUtils.formatTestCaseTitle(testMethod.getName());
+    }
+
+    private static String getClassName(MethodSource testSource) {
+        Class<?> testClass;
+        try {
+            testClass = Class.forName(testSource.getClassName());
+        } catch (ClassNotFoundException e) {
+            log.error(e.getMessage());
+            return null;
+        }
+        return testClass.getSimpleName();
+    }
+}

+ 12 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/annotation/AutomationStatus.java

@@ -0,0 +1,12 @@
+package com.provectus.kafka.ui.utils.qaseIO.annotation;
+
+import com.provectus.kafka.ui.utils.qaseIO.Status;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AutomationStatus {
+
+    Status status();
+}

+ 10 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utils/qaseIO/annotation/Suite.java

@@ -0,0 +1,10 @@
+package com.provectus.kafka.ui.utils.qaseIO.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Suite {
+    long suiteId();
+    String title();
+}

+ 1 - 0
kafka-ui-e2e-checks/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener

@@ -0,0 +1 @@
+com.provectus.kafka.ui.extensions.QaseExtension

+ 5 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/SmokeTests.java

@@ -1,12 +1,17 @@
 package com.provectus.kafka.ui;
 
 import com.provectus.kafka.ui.base.BaseTest;
+import com.provectus.kafka.ui.utils.qaseIO.Status;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.AutomationStatus;
+import io.qase.api.annotation.CaseId;
 import lombok.SneakyThrows;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 
 public class SmokeTests extends BaseTest {
     @Test
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(198)
     @SneakyThrows
     @DisplayName("main page should load")
     void mainPageLoads() {

+ 13 - 6
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/base/BaseTest.java

@@ -4,9 +4,11 @@ import com.codeborne.selenide.Configuration;
 import com.codeborne.selenide.WebDriverRunner;
 import com.codeborne.selenide.logevents.SelenideLogger;
 import com.provectus.kafka.ui.helpers.Helpers;
+import com.provectus.kafka.ui.helpers.TestConfiguration;
 import com.provectus.kafka.ui.pages.Pages;
 import com.provectus.kafka.ui.screenshots.Screenshooter;
-import com.provectus.kafka.ui.steps.Steps;
+import com.provectus.kafka.ui.utils.CamelCaseToSpacedDisplayNameGenerator;
+import com.provectus.kafka.ui.utils.qaseIO.TestCaseGenerator;
 import io.github.cdimascio.dotenv.Dotenv;
 import io.qameta.allure.Allure;
 import io.qameta.allure.selenide.AllureSelenide;
@@ -33,7 +35,6 @@ import java.util.Arrays;
 @DisplayNameGeneration(CamelCaseToSpacedDisplayNameGenerator.class)
 public class BaseTest {
 
-    protected Steps steps = Steps.INSTANCE;
     protected Pages pages = Pages.INSTANCE;
     protected Helpers helpers = Helpers.INSTANCE;
 
@@ -52,7 +53,7 @@ public class BaseTest {
     }
 
     @BeforeEach
-    public void setWebDriver(){
+    public void setWebDriver() {
         RemoteWebDriver remoteWebDriver = webDriverContainer.getWebDriver();
         WebDriverRunner.setWebDriver(remoteWebDriver);
         remoteWebDriver.manage().window().setSize(new Dimension(1440, 1024));
@@ -72,8 +73,8 @@ public class BaseTest {
     }
 
     @AfterAll
-    public static void tearDown(){
-        if(webDriverContainer.isRunning()) {
+    public static void tearDown() {
+        if (webDriverContainer.isRunning()) {
             webDriverContainer.close();
             webDriverContainer.stop();
         }
@@ -93,6 +94,12 @@ public class BaseTest {
             clearReports();
         }
         setup();
+        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+                if (TestCaseGenerator.FAILED) {
+                    log.error("Tests FAILED because some problem with @CaseId annotation. Verify that all tests annotated with @CaseId and Id is correct!");
+                    Runtime.getRuntime().halt(100500);
+                }
+        }));
     }
 
     @AfterEach
@@ -115,7 +122,7 @@ public class BaseTest {
     }
 
     public static void clearReports() {
-        log.info("Clearing reports dir [%s]...".formatted(TestConfiguration.REPORTS_FOLDER));
+        log.info(String.format("Clearing reports dir [%s]...", TestConfiguration.REPORTS_FOLDER));
         File allureResults = new File(TestConfiguration.REPORTS_FOLDER);
         if (allureResults.isDirectory()) {
             File[] list = allureResults.listFiles();

+ 18 - 3
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/ConnectorsTests.java

@@ -4,14 +4,20 @@ import com.provectus.kafka.ui.base.BaseTest;
 import com.provectus.kafka.ui.extensions.FileUtils;
 import com.provectus.kafka.ui.helpers.ApiHelper;
 import com.provectus.kafka.ui.helpers.Helpers;
+import com.provectus.kafka.ui.utils.qaseIO.Status;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.AutomationStatus;
+import io.qase.api.annotation.CaseId;
 import lombok.SneakyThrows;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.Suite;
 
 public class ConnectorsTests extends BaseTest {
 
+    private final long suiteId = 10;
+    private final String suiteTitle = "Kafka Connect";
     public static final String LOCAL_CLUSTER = "local";
     public static final String SINK_CONNECTOR = "sink_postgres_activities_e2e_checks";
     public static final String TOPIC_FOR_CONNECTOR = "topic_for_connector";
@@ -58,6 +64,9 @@ public class ConnectorsTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should create a connector")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(42)
     @Test
     public void createConnector() {
         pages.openConnectorsList(LOCAL_CLUSTER)
@@ -74,26 +83,32 @@ public class ConnectorsTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should update a connector")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(196)
     @Test
     public void updateConnector() {
         pages.openConnectorsList(LOCAL_CLUSTER)
                 .isOnPage()
                 .openConnector(CONNECTOR_FOR_UPDATE);
-                pages.connectorsView.connectorIsVisibleOnOverview();
+        pages.connectorsView.connectorIsVisibleOnOverview();
         pages.connectorsView.openEditConfig()
-                        .updConnectorConfig(FileUtils.getResourceAsString("config_for_update_connector.json"));
+                .updConnectorConfig(FileUtils.getResourceAsString("config_for_update_connector.json"));
         pages.openConnectorsList(LOCAL_CLUSTER)
                 .connectorIsVisibleInList(CONNECTOR_FOR_UPDATE, TOPIC_FOR_UPDATE_CONNECTOR);
     }
 
     @SneakyThrows
     @DisplayName("should delete connector")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(195)
     @Test
     public void deleteConnector() {
         pages.openConnectorsList(LOCAL_CLUSTER)
                 .isOnPage()
                 .openConnector(CONNECTOR_FOR_DELETE);
-                pages.connectorsView.clickDeleteButton();
+        pages.connectorsView.clickDeleteButton();
         pages.openConnectorsList(LOCAL_CLUSTER)
                 .isNotVisible(CONNECTOR_FOR_DELETE);
     }

+ 30 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/SchemasTests.java

@@ -6,14 +6,22 @@ import com.provectus.kafka.ui.base.BaseTest;
 import com.provectus.kafka.ui.helpers.Helpers;
 import com.provectus.kafka.ui.pages.MainPage;
 import com.provectus.kafka.ui.pages.schema.SchemaCreateView;
+import com.provectus.kafka.ui.utils.qaseIO.Status;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.AutomationStatus;
+import io.qase.api.annotation.CaseId;
 import lombok.SneakyThrows;
 import org.junit.jupiter.api.*;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.Suite;
+
+import java.io.IOException;
 
 import static org.apache.kafka.common.utils.Utils.readFileAsString;
 
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 public class SchemasTests extends BaseTest {
 
+    private final long suiteId = 11;
+    private final String suiteTitle = "Schema Registry";
     public static final String SECOND_LOCAL = "secondLocal";
     public static final String SCHEMA_AVRO_CREATE = "avro_schema";
     public static final String SCHEMA_JSON_CREATE = "json_schema";
@@ -49,11 +57,13 @@ public class SchemasTests extends BaseTest {
 
     }
 
-    @SneakyThrows
     @DisplayName("should create AVRO schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(43)
     @Test
     @Order(1)
-    void createSchemaAvro() {
+    void createSchemaAvro() throws IOException {
         pages.openMainPage()
                 .goToSideMenu(SECOND_LOCAL, MainPage.SideMenuOptions.SCHEMA_REGISTRY);
         pages.schemaRegistry.clickCreateSchema()
@@ -69,6 +79,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should update AVRO schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(186)
     @Test
     @Order(2)
     void updateSchemaAvro() {
@@ -86,6 +99,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should delete AVRO schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(187)
     @Test
     @Order(3)
     void deleteSchemaAvro() {
@@ -99,6 +115,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should create JSON schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(89)
     @Test
     @Order(4)
     void createSchemaJson() {
@@ -117,6 +136,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should delete JSON schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(189)
     @Test
     @Order(5)
     void deleteSchemaJson() {
@@ -130,6 +152,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should create PROTOBUF schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(91)
     @Test
     @Order(6)
     void createSchemaProtobuf() {
@@ -148,6 +173,9 @@ public class SchemasTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should delete PROTOBUF schema")
+    @Suite(suiteId = suiteId, title = suiteTitle)
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(223)
     @Test
     @Order(7)
     void deleteSchemaProtobuf() {

+ 19 - 8
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/tests/TopicTests.java

@@ -4,13 +4,16 @@ import com.provectus.kafka.ui.base.BaseTest;
 import com.provectus.kafka.ui.helpers.Helpers;
 import com.provectus.kafka.ui.pages.MainPage;
 import com.provectus.kafka.ui.pages.topic.TopicView;
+import com.provectus.kafka.ui.utils.qaseIO.Status;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.AutomationStatus;
+import com.provectus.kafka.ui.utils.qaseIO.annotation.Suite;
 import io.qameta.allure.Issue;
+import io.qase.api.annotation.CaseId;
 import lombok.SneakyThrows;
 import org.junit.jupiter.api.*;
 
 import static org.apache.kafka.common.utils.Utils.readFileAsString;
 
-
 public class TopicTests extends BaseTest {
 
     public static final String NEW_TOPIC = "new-topic";
@@ -25,8 +28,6 @@ public class TopicTests extends BaseTest {
     private static final String CONTENT_TO_PRODUCE_MESSAGE = System.getProperty("user.dir") + "/src/test/resources/testData.txt";
 
 
-
-
     @BeforeAll
     @SneakyThrows
     public static void beforeAll() {
@@ -44,6 +45,9 @@ public class TopicTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should create a topic")
+    @Suite(suiteId = 4, title = "Create new Topic")
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(199)
     @Test
     public void createTopic() {
         pages.open()
@@ -65,6 +69,9 @@ public class TopicTests extends BaseTest {
     @SneakyThrows
     @DisplayName("should update a topic")
     @Issue("1500")
+    @Suite(suiteId = 2, title = "Topics")
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(197)
     @Test
     public void updateTopic() {
         pages.openTopicsList(SECOND_LOCAL)
@@ -93,6 +100,9 @@ public class TopicTests extends BaseTest {
 
     @SneakyThrows
     @DisplayName("should delete topic")
+    @Suite(suiteId = 2, title = "Topics")
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(207)
     @Test
     public void deleteTopic() {
         pages.openTopicsList(SECOND_LOCAL)
@@ -104,12 +114,13 @@ public class TopicTests extends BaseTest {
                 .isTopicNotVisible(TOPIC_TO_DELETE);
     }
 
-    @Disabled("Due to issue https://github.com/provectus/kafka-ui/issues/2140 ignore this test")
-    @Issue("2140")
     @SneakyThrows
     @DisplayName("produce message")
+    @Suite(suiteId = 2, title = "Topics")
+    @AutomationStatus(status = Status.AUTOMATED)
+    @CaseId(222)
     @Test
-    void produceMessage(){
+    void produceMessage() {
         pages.openTopicsList(SECOND_LOCAL)
                 .isOnPage()
                 .openTopic(TOPIC_TO_UPDATE)
@@ -119,7 +130,7 @@ public class TopicTests extends BaseTest {
                 .setContentFiled(readFileAsString(CONTENT_TO_PRODUCE_MESSAGE))
                 .setKeyField(readFileAsString(KEY_TO_PRODUCE_MESSAGE))
                 .submitProduceMessage();
-                Assertions.assertTrue(pages.topicView.isKeyMessageVisible(readFileAsString(KEY_TO_PRODUCE_MESSAGE)));
-                Assertions.assertTrue(pages.topicView.isContentMessageVisible(readFileAsString(CONTENT_TO_PRODUCE_MESSAGE)));
+        Assertions.assertTrue(pages.topicView.isKeyMessageVisible(readFileAsString(KEY_TO_PRODUCE_MESSAGE)));
+        Assertions.assertTrue(pages.topicView.isContentMessageVisible(readFileAsString(CONTENT_TO_PRODUCE_MESSAGE).trim()));
     }
 }