浏览代码

Merge branch 'master' into Topic_custom_params_are_disabled_upon_editing

Oleg Shur 2 年之前
父节点
当前提交
48231798bb

+ 1 - 0
.github/workflows/e2e-checks.yaml

@@ -52,6 +52,7 @@ jobs:
           gh_pages: allure-results
           allure_report: allure-report
           subfolder: allure-results
+          report_url: "http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com"
       - uses: jakejarvis/s3-sync-action@master
         if: always()
         env:

+ 6 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java

@@ -18,6 +18,7 @@ public abstract class BasePage extends WebUtils {
   protected SelenideElement dotMenuBtn = $x("//button[@aria-label='Dropdown Toggle']");
   protected SelenideElement alertHeader = $x("//div[@role='alert']//div[@role='heading']");
   protected SelenideElement alertMessage = $x("//div[@role='alert']//div[@role='contentinfo']");
+  protected SelenideElement confirmBtn = $x("//button[contains(text(),'Confirm')]");
   protected ElementsCollection allGridItems = $$x("//tr[@class]");
   protected String summaryCellLocator = "//div[contains(text(),'%s')]";
   protected String tableElementNameLocator = "//tbody//a[contains(text(),'%s')]";
@@ -65,6 +66,11 @@ public abstract class BasePage extends WebUtils {
     return result;
   }
 
+  protected void clickConfirmButton() {
+    confirmBtn.shouldBe(Condition.enabled).click();
+    confirmBtn.shouldBe(Condition.disappear);
+  }
+
   public enum AlertHeader {
     SUCCESS("Success"),
     VALIDATION_ERROR("Validation Error"),

+ 2 - 4
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicDetails.java

@@ -36,7 +36,6 @@ public class TopicDetails extends BasePage {
   protected SelenideElement selectFilterBtnAddFilterMdl = $x("//button[text()='Select filter']");
   protected SelenideElement editSettingsMenu = $x("//li[@role][contains(text(),'Edit settings')]");
   protected SelenideElement removeTopicBtn = $x("//ul[@role='menu']//div[contains(text(),'Remove Topic')]");
-  protected SelenideElement confirmBtn = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]");
   protected SelenideElement produceMessageBtn = $x("//div//button[text()='Produce Message']");
   protected SelenideElement contentMessageTab = $x("//html//div[@id='root']/div/main//table//p");
   protected SelenideElement cleanUpPolicyField = $x("//div[contains(text(),'Clean Up Policy')]/../span/*");
@@ -77,7 +76,7 @@ public class TopicDetails extends BasePage {
   }
 
   @Step
-  public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
+  public boolean isAlertWithMessageVisible(AlertHeader header, String message){
     return isAlertVisible(header, message);
   }
 
@@ -127,8 +126,7 @@ public class TopicDetails extends BasePage {
 
   @Step
   public TopicDetails clickConfirmBtnMdl() {
-    confirmBtn.shouldBe(Condition.enabled).click();
-    confirmBtn.shouldBe(Condition.disappear);
+    clickConfirmButton();
     return this;
   }
 

+ 40 - 7
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topic/TopicsList.java

@@ -1,5 +1,6 @@
 package com.provectus.kafka.ui.pages.topic;
 
+import static com.codeborne.selenide.Condition.visible;
 import static com.codeborne.selenide.Selenide.$x;
 
 import com.codeborne.selenide.CollectionCondition;
@@ -7,6 +8,7 @@ import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -22,11 +24,13 @@ public class TopicsList extends BasePage {
     protected SelenideElement deleteSelectedTopicsBtn = $x("//button[text()='Delete selected topics']");
     protected SelenideElement copySelectedTopicBtn = $x("//button[text()='Copy selected topic']");
     protected SelenideElement purgeMessagesOfSelectedTopicsBtn = $x("//button[text()='Purge messages of selected topics']");
+    protected SelenideElement clearMessagesBtn = $x("//ul[contains(@class ,'open')]//div[text()='Clear Messages']");
+    protected SelenideElement recreateTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Recreate Topic']");
 
     @Step
     public TopicsList waitUntilScreenReady() {
         waitUntilSpinnerDisappear();
-        topicListHeader.shouldBe(Condition.visible);
+        topicListHeader.shouldBe(visible);
         return this;
     }
 
@@ -38,7 +42,7 @@ public class TopicsList extends BasePage {
 
     @Step
     public boolean isTopicVisible(String topicName) {
-        tableGrid.shouldBe(Condition.visible);
+        tableGrid.shouldBe(visible);
         return isVisible(getTableElement(topicName));
     }
 
@@ -59,6 +63,12 @@ public class TopicsList extends BasePage {
         return this;
     }
 
+    @Step
+    public TopicsList openDotMenuByTopicName(String topicName){
+      getTopicItem(topicName).openDotMenu();
+      return this;
+    }
+
     @Step
     public boolean isCopySelectedTopicBtnEnabled(){
       return isEnabled(copySelectedTopicBtn);
@@ -76,6 +86,29 @@ public class TopicsList extends BasePage {
       return this;
     }
 
+    @Step
+    public TopicsList clickClearMessagesBtn(){
+      clickByJavaScript(clearMessagesBtn.shouldBe(visible));
+      return this;
+    }
+
+    @Step
+    public TopicsList clickRecreateTopicBtn(){
+      clickByJavaScript(recreateTopicBtn.shouldBe(visible));
+      return this;
+    }
+
+    @Step
+    public TopicsList clickConfirmBtnMdl() {
+    clickConfirmButton();
+    return this;
+    }
+
+    @Step
+    public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
+      return isAlertVisible(header, message);
+    }
+
     private List<SelenideElement> getVisibleColumnHeaders() {
       return Stream.of("Replication Factor","Number of messages","Topic Name", "Partitions", "Out of sync replicas", "Size")
           .map(name -> $x(String.format(columnHeaderLocator, name)))
@@ -110,12 +143,12 @@ public class TopicsList extends BasePage {
       return gridItemList;
     }
 
-  @Step
-  public TopicGridItem getTopicItem(String name) {
-    return initGridItems().stream()
+    @Step
+    public TopicGridItem getTopicItem(String name) {
+      return initGridItems().stream()
         .filter(e -> e.getName().equals(name))
         .findFirst().orElse(null);
-  }
+    }
 
     @Step
     public List<TopicGridItem> getNonInternalTopics() {
@@ -149,7 +182,7 @@ public class TopicsList extends BasePage {
       public boolean isInternal() {
         boolean internal = false;
         try {
-          element.$x("./td[2]/a/span").shouldBe(Condition.visible);
+          element.$x("./td[2]/a/span").shouldBe(visible, Duration.ofMillis(500));
           internal = true;
         } catch (Throwable ignored) {
         }

+ 81 - 2
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/suite/topics/TopicMessagesTests.java

@@ -5,6 +5,7 @@ import static com.provectus.kafka.ui.pages.topic.TopicDetails.TopicMenu.MESSAGES
 import static com.provectus.kafka.ui.settings.BaseSource.CLUSTER_NAME;
 import static com.provectus.kafka.ui.utilities.FileUtils.fileToString;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import com.provectus.kafka.ui.base.BaseTest;
 import com.provectus.kafka.ui.models.Topic;
@@ -33,11 +34,19 @@ public class TopicMessagesTests extends BaseTest {
       .setName("topic-with-clean-message-attribute-" + randomAlphabetic(5))
       .setMessageKey(fileToString(System.getProperty("user.dir") + "/src/test/resources/producedkey.txt"))
       .setMessageContent(fileToString(System.getProperty("user.dir") + "/src/test/resources/testData.txt"));
+  private static final Topic TOPIC_TO_CLEAR_MESSAGES = new Topic()
+      .setName("topic-to-clear-message-attribute-" + randomAlphabetic(5))
+      .setMessageKey(fileToString(System.getProperty("user.dir") + "/src/test/resources/producedkey.txt"))
+      .setMessageContent(fileToString(System.getProperty("user.dir") + "/src/test/resources/testData.txt"));
+  private static final Topic TOPIC_TO_RECREATE = new Topic()
+      .setName("topic-to-recreate-attribute-" + randomAlphabetic(5))
+      .setMessageKey(fileToString(System.getProperty("user.dir") + "/src/test/resources/producedkey.txt"))
+      .setMessageContent(fileToString(System.getProperty("user.dir") + "/src/test/resources/testData.txt"));
   private static final List<Topic> TOPIC_LIST = new ArrayList<>();
 
   @BeforeAll
   public void beforeAll() {
-    TOPIC_LIST.addAll(List.of(TOPIC_FOR_MESSAGES));
+    TOPIC_LIST.addAll(List.of(TOPIC_FOR_MESSAGES, TOPIC_TO_CLEAR_MESSAGES, TOPIC_TO_RECREATE));
     TOPIC_LIST.forEach(topic -> apiService.createTopic(CLUSTER_NAME, topic.getName()));
   }
 
@@ -108,7 +117,7 @@ public class TopicMessagesTests extends BaseTest {
         .getRandomMessage()
         .openDotMenu()
         .clickCopyToClipBoard();
-    Assertions.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS, "Copied successfully!"),
+    Assertions.assertTrue(topicDetails.isAlertWithMessageVisible(SUCCESS,"Copied successfully!"),
         "isAlertWithMessageVisible()");
   }
 
@@ -134,6 +143,76 @@ public class TopicMessagesTests extends BaseTest {
     softly.assertAll();
   }
 
+  @DisplayName("TopicTests.clearMessageOfTopic : Clear message of topic")
+  @Suite(suiteId = SUITE_ID, title = SUITE_TITLE)
+  @AutomationStatus(status = Status.AUTOMATED)
+  @CaseId(239)
+  @Test
+  void checkClearTopicMessage() {
+    navigateToTopicsAndOpenDetails(TOPIC_TO_CLEAR_MESSAGES.getName());
+    topicDetails
+        .openDetailsTab(TopicDetails.TopicMenu.OVERVIEW)
+        .clickProduceMessageBtn();
+    produceMessagePanel
+        .waitUntilScreenReady()
+        .setContentFiled(TOPIC_TO_CLEAR_MESSAGES.getMessageContent())
+        .setKeyField(TOPIC_TO_CLEAR_MESSAGES.getMessageKey())
+        .submitProduceMessage();
+    topicDetails
+        .waitUntilScreenReady();
+    navigateToTopics();
+    topicsList
+        .waitUntilScreenReady();
+    assertThat(topicsList.getTopicItem(TOPIC_TO_CLEAR_MESSAGES.getName()).getNumberOfMessages())
+        .as("getNumberOfMessages()").isEqualTo(1);
+    topicsList
+        .openDotMenuByTopicName(TOPIC_TO_CLEAR_MESSAGES.getName())
+        .clickClearMessagesBtn()
+        .clickConfirmBtnMdl();
+    SoftAssertions softly = new SoftAssertions();
+    softly.assertThat(topicsList.isAlertWithMessageVisible(SUCCESS,
+        String.format("%s messages have been successfully cleared!",TOPIC_TO_CLEAR_MESSAGES.getName())))
+        .as("isAlertWithMessageVisible()").isTrue();
+    softly.assertThat(topicsList.getTopicItem(TOPIC_TO_CLEAR_MESSAGES.getName()).getNumberOfMessages())
+        .as("getNumberOfMessages()").isEqualTo(0);
+    softly.assertAll();
+  }
+
+  @DisplayName("TopicTests.recreateTopic : Recreate topic")
+  @Suite(suiteId = SUITE_ID, title = SUITE_TITLE)
+  @AutomationStatus(status = Status.AUTOMATED)
+  @CaseId(240)
+  @Test
+  void checkRecreateTopic(){
+    navigateToTopicsAndOpenDetails(TOPIC_TO_RECREATE.getName());
+    topicDetails
+        .openDetailsTab(TopicDetails.TopicMenu.OVERVIEW)
+        .clickProduceMessageBtn();
+    produceMessagePanel
+        .waitUntilScreenReady()
+        .setContentFiled(TOPIC_TO_RECREATE.getMessageContent())
+        .setKeyField(TOPIC_TO_RECREATE.getMessageKey())
+        .submitProduceMessage();
+    topicDetails
+        .waitUntilScreenReady();
+    navigateToTopics();
+    topicsList
+        .waitUntilScreenReady();
+    assertThat(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages())
+        .as("getNumberOfMessages()").isEqualTo(1);
+    topicsList
+        .openDotMenuByTopicName(TOPIC_TO_RECREATE.getName())
+        .clickRecreateTopicBtn()
+        .clickConfirmBtnMdl();
+    SoftAssertions softly = new SoftAssertions();
+    softly.assertThat(topicDetails.isAlertWithMessageVisible(SUCCESS,
+            String.format("Topic %s successfully recreated!", TOPIC_TO_RECREATE.getName())))
+        .as("isAlertWithMessageVisible()").isTrue();
+    softly.assertThat(topicsList.getTopicItem(TOPIC_TO_RECREATE.getName()).getNumberOfMessages())
+        .as("getNumberOfMessages()").isEqualTo(0);
+    softly.assertAll();
+  }
+
   @AfterAll
   public void afterAll() {
     TOPIC_LIST.forEach(topic -> apiService.deleteTopic(CLUSTER_NAME, topic.getName()));

+ 0 - 1
kafka-ui-react-app/package.json

@@ -19,7 +19,6 @@
     "@types/testing-library__jest-dom": "^5.14.5",
     "ace-builds": "^1.7.1",
     "ajv": "^8.6.3",
-    "classnames": "^2.2.6",
     "fetch-mock": "^9.11.0",
     "jest": "^29.0.3",
     "jest-watch-typeahead": "^2.0.0",

+ 0 - 2
kafka-ui-react-app/pnpm-lock.yaml

@@ -38,7 +38,6 @@ specifiers:
   '@vitejs/plugin-react-swc': ^3.0.0
   ace-builds: ^1.7.1
   ajv: ^8.6.3
-  classnames: ^2.2.6
   dotenv: ^16.0.1
   eslint: ^8.3.0
   eslint-config-airbnb: ^19.0.4
@@ -107,7 +106,6 @@ dependencies:
   '@types/testing-library__jest-dom': 5.14.5
   ace-builds: 1.7.1
   ajv: 8.8.2
-  classnames: 2.3.1
   fetch-mock: 9.11.0
   jest: 29.0.3_yqiaopbgmqcuvx27p5xxvum6wm
   jest-watch-typeahead: 2.0.0_jest@29.0.3

+ 6 - 11
kafka-ui-react-app/src/components/ConsumerGroups/Details/Details.tsx

@@ -18,10 +18,9 @@ import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeader
 import { useAppDispatch, useAppSelector } from 'lib/hooks/redux';
 import {
   deleteConsumerGroup,
+  selectById,
   fetchConsumerGroupDetails,
   getAreConsumerGroupDetailsFulfilled,
-  getIsConsumerGroupDeleted,
-  selectById,
 } from 'redux/reducers/consumerGroups/consumerGroupsSlice';
 import getTagColor from 'components/common/Tag/getTagColor';
 import { Dropdown } from 'components/common/Dropdown';
@@ -41,23 +40,19 @@ const Details: React.FC = () => {
   const consumerGroup = useAppSelector((state) =>
     selectById(state, consumerGroupID)
   );
-  const isDeleted = useAppSelector(getIsConsumerGroupDeleted);
   const isFetched = useAppSelector(getAreConsumerGroupDetailsFulfilled);
 
   React.useEffect(() => {
     dispatch(fetchConsumerGroupDetails({ clusterName, consumerGroupID }));
   }, [clusterName, consumerGroupID, dispatch]);
 
-  const onDelete = () => {
-    dispatch(deleteConsumerGroup({ clusterName, consumerGroupID }));
+  const onDelete = async () => {
+    const res = await dispatch(
+      deleteConsumerGroup({ clusterName, consumerGroupID })
+    ).unwrap();
+    if (res) navigate('../');
   };
 
-  React.useEffect(() => {
-    if (isDeleted) {
-      navigate('../');
-    }
-  }, [clusterName, navigate, isDeleted]);
-
   const onResetOffsets = () => {
     navigate(clusterConsumerGroupResetRelativePath);
   };

+ 0 - 5
kafka-ui-react-app/src/redux/reducers/consumerGroups/consumerGroupsSlice.ts

@@ -195,11 +195,6 @@ export const getAreConsumerGroupsPagedFulfilled = createSelector(
   (status) => status === AsyncRequestStatus.fulfilled
 );
 
-export const getIsConsumerGroupDeleted = createSelector(
-  createFetchingSelector('consumerGroups/deleteConsumerGroup'),
-  (status) => status === AsyncRequestStatus.fulfilled
-);
-
 export const getAreConsumerGroupDetailsFulfilled = createSelector(
   createFetchingSelector('consumerGroups/fetchConsumerGroupDetails'),
   (status) => status === AsyncRequestStatus.fulfilled