NIFIREG-266 Add Selenium UI automated tests for bucket use cases

NIFIREG-266 Corrected check-style violations and added Apache license header to tests

This closes #185.

Signed-off-by: Bryan Bende <bbende@apache.org>
diff --git a/nifi-registry-core/nifi-registry-web-ui/pom.xml b/nifi-registry-core/nifi-registry-web-ui/pom.xml
index 4a0f4e7..52c597c 100644
--- a/nifi-registry-core/nifi-registry-web-ui/pom.xml
+++ b/nifi-registry-core/nifi-registry-web-ui/pom.xml
@@ -367,6 +367,21 @@
                     </excludes>
                 </configuration>
             </plugin>
+            <!--
+                    By default, skip all tests in nifi-registry-web-ui directory during build.
+            -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>none</phase>
+                    </execution>
+                </executions>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
     <profiles>
@@ -484,5 +499,60 @@
                 </plugins>
             </build>
         </profile>
+        <!--
+            Profile to explicitly run Selenium UI tests during build.
+        -->
+        <profile>
+            <id>selenium_tests</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <configuration>
+                            <skip>false</skip>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                                <phase>verify</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
+    <dependencies>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-firefox-driver</artifactId>
+            <version>3.141.59</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-chrome-driver</artifactId>
+            <version>3.141.59</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-server</artifactId>
+            <version>3.141.59</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.github.bonigarcia</groupId>
+            <artifactId>webdrivermanager</artifactId>
+            <version>3.3.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html b/nifi-registry-core/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
index 494521c..a93ac7e 100644
--- a/nifi-registry-core/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
+++ b/nifi-registry-core/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
@@ -26,6 +26,7 @@
         <div class="pad-left-md pad-right-md" flex fxLayoutAlign="start center">
             <mat-input-container flex>
                 <input #bucketnameInput
+                       data-automation-id="nf-registry-manage-bucket-input-name"
                        matInput
                        [disabled]="!nfRegistryService.currentUser.resourcePermissions.buckets.canWrite"
                        placeholder="Identity/Bucket Name"
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucket.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucket.java
new file mode 100644
index 0000000..5768748
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucket.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITCreateBucket {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testCreateBucket() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn")));
+        confirmDelete.click();
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucketCancel.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucketCancel.java
new file mode 100644
index 0000000..86d17db
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateBucketCancel.java
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import static org.junit.Assert.fail;
+
+public class ITCreateBucketCancel {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testCreateBucketCancel() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm cancel button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog button.mat-fds-regular")));
+
+        // select cancel button
+        WebElement cancelButton = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog button.mat-fds-regular"));
+        cancelButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm no buckets exist
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+    }
+
+
+    @After
+    public void tearDown() throws Exception {
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateDuplicateBucket.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateDuplicateBucket.java
new file mode 100644
index 0000000..301519a
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateDuplicateBucket.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITCreateDuplicateBucket {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testCreateDuplicateBucket() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for create bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        bucketNameInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+        bucketNameInput.clear();
+
+        // name the bucket ABC again
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for the new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // wait for error dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // confirm the duplicate bucket error
+        WebElement selectOKButton = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+        Actions actions = new Actions(driver);
+        actions.moveToElement(selectOKButton).click().build().perform();
+
+        // wait for the confirm dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // verify bucket ABC still there
+        bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn")));
+        confirmDelete.click();
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateMultipleBuckets.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateMultipleBuckets.java
new file mode 100644
index 0000000..54f54aa
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITCreateMultipleBuckets.java
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITCreateMultipleBuckets {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testCreateMultipleBuckets() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm keep dialog open checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#mat-checkbox-2 > label.mat-checkbox-layout > div.mat-checkbox-inner-container")));
+
+        // select keep dialog open checkbox
+        WebElement keepOpenCheckbox = driver.findElement(By.cssSelector("#mat-checkbox-2 > label.mat-checkbox-layout > div.mat-checkbox-inner-container"));
+        keepOpenCheckbox.click();
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        bucketNameInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+        bucketNameInput.clear();
+
+        // name the bucket DEF
+        bucketNameInput.sendKeys("DEF");
+
+        // confirm keep dialog open checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#mat-checkbox-2 > label.mat-checkbox-layout > div.mat-checkbox-inner-container")));
+
+        // select keep dialog open checkbox
+        keepOpenCheckbox = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#mat-checkbox-2 > label.mat-checkbox-layout > div.mat-checkbox-inner-container")));
+        keepOpenCheckbox.click();
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(2, bucketCount.size());
+    }
+
+
+    @After
+    public void tearDown() throws Exception {
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn")));
+        confirmDelete.click();
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucket.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucket.java
new file mode 100644
index 0000000..53ba453
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucket.java
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITDeleteSingleBucket {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testDeleteSingleBucket() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+
+        // confirm trash icon button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("fa-trash")));
+
+        // select trash icon for ABC bucket
+        WebElement manageBucketButton = driver.findElement(By.className("fa-trash"));
+        manageBucketButton.click();
+
+        // wait for confirm dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // confirm delete button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane button.mat-fds-warn")));
+
+        // select delete button
+        WebElement deleteButton = driver.findElement(By.cssSelector("div.cdk-overlay-pane button.mat-fds-warn"));
+        deleteButton.click();
+
+        // wait for the confirm dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // confirm no buckets exist
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucketCancel.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucketCancel.java
new file mode 100644
index 0000000..80a34c2
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITDeleteSingleBucketCancel.java
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITDeleteSingleBucketCancel {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testDeleteSingleBucketCancel() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for create bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+
+        // confirm trash icon button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("fa-trash")));
+
+        // select trash icon for ABC bucket
+        WebElement manageBucketButton = driver.findElement(By.className("fa-trash"));
+        manageBucketButton.click();
+
+        // wait for confirm dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // confirm cancel button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane button.mat-fds-regular")));
+
+        // select cancel button
+        WebElement cancelButton = driver.findElement(By.cssSelector("div.cdk-overlay-pane button.mat-fds-regular"));
+        cancelButton.click();
+
+        // verify bucket ABC still there
+        bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = driver.findElement(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn"));
+        executor.executeScript("arguments[0].click();", confirmDelete);
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucket.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucket.java
new file mode 100644
index 0000000..917faa6
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucket.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITRenameBucket {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testRenameBucket() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+
+        // confirm pencil icon button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("fa-pencil")));
+
+        // select pencil icon for ABC bucket
+        WebElement manageBucketButton = driver.findElement(By.className("fa-pencil"));
+        manageBucketButton.click();
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-input-name']")));
+
+        // place cursor in Identity/Bucket Name Field
+        WebElement identityBucketNameInput = driver.findElement(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-input-name']"));
+        identityBucketNameInput.clear();
+
+        // name the bucket DEF
+        identityBucketNameInput.sendKeys("DEF");
+
+        // confirm save button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-save-side-nav']")));
+
+        // select save button
+        WebElement saveBucketButton = driver.findElement(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-save-side-nav']"));
+        saveBucketButton.click();
+
+        // close side nav via "x"
+        WebElement closeSideNavX = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-close-side-nav']")));
+        Actions actions = new Actions(driver);
+        actions.moveToElement(closeSideNavX).click().build().perform();
+
+        // wait for side nav to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-close-side-nav']")));
+
+        // verify renamed bucket exists
+        bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // wait for side nav to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.className("mat-sidenav")));
+
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn")));
+        confirmDelete.click();
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucketDuplicate.java b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucketDuplicate.java
new file mode 100644
index 0000000..ec15a68
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-web-ui/src/test/java/org/apache/nifi/registry/ui/ITRenameBucketDuplicate.java
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+package org.apache.nifi.registry.ui;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import io.github.bonigarcia.wdm.WebDriverManager;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ITRenameBucketDuplicate {
+    private WebDriver driver;
+    private String baseUrl;
+    private boolean acceptNextAlert = true;
+    private WebDriverWait wait;
+    private StringBuffer verificationErrors = new StringBuffer();
+
+    @Before
+    public void setUp() throws Exception {
+        WebDriverManager.chromedriver().setup();
+        driver = new ChromeDriver();
+        baseUrl = "http://localhost:18080/nifi-registry";
+        wait = new WebDriverWait(driver, 30);
+    }
+
+    @Test
+    public void testRenameBucketDuplicate() throws Exception {
+        // go directly to settings by URL
+        driver.get(baseUrl + "/administration/workflow");
+
+        // wait for administration route to load
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        WebElement newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        WebElement bucketNameInput = driver.findElement(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input"));
+        bucketNameInput.clear();
+
+        // name the bucket ABC
+        bucketNameInput.sendKeys("ABC");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        WebElement createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for create bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        List<WebElement> bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(1, bucketCount.size());
+
+        // confirm new bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='new-bucket-button']")));
+
+        // select new bucket button
+        newBucketButton = driver.findElement(By.cssSelector("[data-automation-id='new-bucket-button']"));
+        newBucketButton.click();
+
+        // wait for new bucket dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+
+        // place cursor in bucket name field
+        bucketNameInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog input")));
+        bucketNameInput.clear();
+
+        // name the bucket DEF
+        bucketNameInput.sendKeys("DEF");
+
+        // confirm create bucket button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='create-new-bucket-button']")));
+
+        // select create bucket button
+        createNewBucketButton = driver.findElement(By.cssSelector("[data-automation-id='create-new-bucket-button']"));
+        createNewBucketButton.click();
+
+        // wait for new bucket dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("#nifi-registry-admin-create-bucket-dialog")));
+
+        // verify bucket added
+        bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(2, bucketCount.size());
+
+        // confirm pencil icon button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("fa-pencil")));
+
+        // select pencil icon for ABC bucket
+        WebElement manageBucketButton = driver.findElement(By.className("fa-pencil"));
+        manageBucketButton.click();
+
+        // confirm bucket name field exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-input-name']")));
+
+        // place cursor in Bucket Name Field
+        WebElement identityBucketNameInput = driver.findElement(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-input-name']"));
+        identityBucketNameInput.clear();
+
+        // name the bucket DEF
+        identityBucketNameInput.sendKeys("DEF");
+
+        // confirm save button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-save-side-nav']")));
+
+        // select save button
+        WebElement saveBucketButton = driver.findElement(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-save-side-nav']"));
+        saveBucketButton.click();
+
+        // wait for duplicate bucket error dialog
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+
+        // confirm OK button exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("fds-confirm-dialog > fds-dialog > div > div.fds-dialog-actions.ng-star-inserted > fds-dialog-actions > button")));
+
+        // select OK button
+        WebElement selectOKButton = driver.findElement(By.cssSelector("fds-confirm-dialog > fds-dialog > div > div.fds-dialog-actions.ng-star-inserted > fds-dialog-actions > button"));
+        Actions actions = new Actions(driver);
+        actions.moveToElement(selectOKButton).click().build().perform();
+
+        // wait for the confirm dialog to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.cdk-overlay-pane")));
+
+        // close side nav via "x"
+        WebElement closeSideNavX = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-close-side-nav']")));
+        actions.moveToElement(closeSideNavX).click().build().perform();
+
+        // wait for side nav to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("[data-automation-id='nf-registry-manage-bucket-close-side-nav']")));
+
+        // verify both buckets exists
+        bucketCount = driver.findElements(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container > div"));
+        assertEquals(2, bucketCount.size());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // wait for side nav to close
+        wait.until(ExpectedConditions.invisibilityOfElementLocated(By.className("mat-sidenav")));
+
+        // bucket cleanup
+
+        // confirm all buckets checkbox exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container")));
+
+        // select all buckets checkbox
+        WebElement selectAllCheckbox = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-buckets-list-container-column-header div.mat-checkbox-inner-container"));
+        selectAllCheckbox.click();
+
+        // confirm actions drop down menu exists
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary")));
+
+        // select actions drop down
+        WebElement selectActions = driver.findElement(By.cssSelector("#nifi-registry-workflow-administration-perspective-buckets-container button.mat-fds-primary"));
+        selectActions.click();
+
+        // select delete
+        WebElement selectDeleteBucket = driver.findElement(By.cssSelector("div.mat-menu-content button.mat-menu-item"));
+        JavascriptExecutor executor = (JavascriptExecutor)driver;
+        executor.executeScript("arguments[0].click();", selectDeleteBucket);
+
+        // verify bucket deleted
+        WebElement confirmDelete = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.fds-dialog-actions button.mat-fds-warn")));
+        confirmDelete.click();
+        wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-automation-id='no-buckets-message']")));
+
+        driver.quit();
+        String verificationErrorString = verificationErrors.toString();
+        if (!"".equals(verificationErrorString)) {
+            fail(verificationErrorString);
+        }
+    }
+
+    private boolean isElementPresent(By by) {
+        try {
+            driver.findElement(by);
+            return true;
+        } catch (NoSuchElementException e) {
+            return false;
+        }
+    }
+
+    private boolean isAlertPresent() {
+        try {
+            driver.switchTo().alert();
+            return true;
+        } catch (NoAlertPresentException e) {
+            return false;
+        }
+    }
+
+    private String closeAlertAndGetItsText() {
+        try {
+            Alert alert = driver.switchTo().alert();
+            String alertText = alert.getText();
+            if (acceptNextAlert) {
+                alert.accept();
+            } else {
+                alert.dismiss();
+            }
+            return alertText;
+        } finally {
+            acceptNextAlert = true;
+        }
+    }
+}
\ No newline at end of file