diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/feature-flags.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/feature-flags.ejs index 0ab4d6a16f55..4d3a78d43d7b 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/feature-flags.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/feature-flags.ejs @@ -20,7 +20,7 @@

-
+

Feature Flags

<%= filter_ui(nonreq_feature_flags) %> diff --git a/selenium/full-suite-management-ui b/selenium/full-suite-management-ui index ceec03793e34..0c39f9278b92 100644 --- a/selenium/full-suite-management-ui +++ b/selenium/full-suite-management-ui @@ -22,3 +22,4 @@ mgt/exchanges.sh mgt/limits.sh mgt/mgt-only-exchanges.sh mgt/queuesAndStreams.sh +mgt/feature-flags.sh \ No newline at end of file diff --git a/selenium/package.json b/selenium/package.json index c79d91274d10..b84708617f62 100644 --- a/selenium/package.json +++ b/selenium/package.json @@ -12,7 +12,7 @@ "author": "", "license": "ISC", "dependencies": { - "chromedriver": "^137.0", + "chromedriver": "^139.0", "ejs": "^3.1.8", "express": "^4.18.2", "geckodriver": "^3.0.2", diff --git a/selenium/short-suite-management-ui b/selenium/short-suite-management-ui index a0d4a3a86c38..03828544c99e 100644 --- a/selenium/short-suite-management-ui +++ b/selenium/short-suite-management-ui @@ -8,4 +8,5 @@ mgt/exchanges.sh mgt/queuesAndStreams.sh mgt/limits.sh mgt/amqp10-connections.sh -mgt/mqtt-connections.sh \ No newline at end of file +mgt/mqtt-connections.sh +mgt/feature-flags.sh \ No newline at end of file diff --git a/selenium/suites/mgt/feature-flags.sh b/selenium/suites/mgt/feature-flags.sh new file mode 100755 index 000000000000..87cd1082aa01 --- /dev/null +++ b/selenium/suites/mgt/feature-flags.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +TEST_CASES_PATH=/feature-flags +TEST_CONFIG_PATH=/basic-auth + +source $SCRIPT/../../bin/suite_template $@ +run diff --git a/selenium/test/feature-flags/feature-flags.js b/selenium/test/feature-flags/feature-flags.js new file mode 100644 index 000000000000..a64afbf5d203 --- /dev/null +++ b/selenium/test/feature-flags/feature-flags.js @@ -0,0 +1,54 @@ +const { By, Key, until, Builder } = require('selenium-webdriver') +require('chromedriver') +const assert = require('assert') +const { buildDriver, goToHome, captureScreensFor, teardown, findTableRow, delay } = require('../utils') + +const LoginPage = require('../pageobjects/LoginPage') +const OverviewPage = require('../pageobjects/OverviewPage') +const AdminTab = require('../pageobjects/AdminTab') +const FeatureFlagsAdminTab = require('../pageobjects/FeatureFlagsAdminTab') + +describe('Feature flags in Admin tab', function () { + let login + let overview + let ffTab + let captureScreen + + before(async function () { + driver = buildDriver() + await goToHome(driver) + login = new LoginPage(driver) + overview = new OverviewPage(driver) + adminTab = new AdminTab(driver) + ffTab = new FeatureFlagsAdminTab(driver) + captureScreen = captureScreensFor(driver, __filename) + + await login.login('guest', 'guest') + if (!await overview.isLoaded()) { + throw new Error('Failed to login') + } + await overview.selectRefreshOption("Do not refresh") + }) + + it('it has at least one feature flag', async function () { + await overview.clickOnAdminTab() + await adminTab.clickOnFeatureFlags() + let ffTable = await ffTab.getAll() + assert(ffTable.length > 0) + }) + it('it has khepri_db feature flag', async function () { + await overview.clickOnAdminTab() + await adminTab.clickOnFeatureFlags() + let ffTable = await ffTab.getAll() + assert(findTableRow(ffTable, function(row) { + return row[0] === 'khepri_db' + })) + let state = await ffTab.getState('khepri_db') + assert(await state.isSelected()) + }) + + + after(async function () { + await teardown(driver, this, captureScreen) + }) +}) diff --git a/selenium/test/pageobjects/BasePage.js b/selenium/test/pageobjects/BasePage.js index 36bad7c4e0b4..63106a1fcbe8 100644 --- a/selenium/test/pageobjects/BasePage.js +++ b/selenium/test/pageobjects/BasePage.js @@ -33,7 +33,14 @@ module.exports = class BasePage { this.polling = parseInt(process.env.SELENIUM_POLLING) || 500 // how frequent selenium searches for an element this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy) } - + async ensureSectionIsVisible(section) { + let classes = await this.driver.findElement(section).getAttribute("class") + if (classes.search('section-visible') < 0) { + return this.click(section) + } else { + return Promise.resolve(true) + } + } async goTo(path) { return driver.get(d.baseUrl + path) } diff --git a/selenium/test/pageobjects/FeatureFlagsAdminTab.js b/selenium/test/pageobjects/FeatureFlagsAdminTab.js new file mode 100644 index 000000000000..9e871a1cd7d3 --- /dev/null +++ b/selenium/test/pageobjects/FeatureFlagsAdminTab.js @@ -0,0 +1,59 @@ +const { By, Key, until, Builder } = require('selenium-webdriver') +const { delay } = require('../utils') + +const AdminTab = require('./AdminTab') + + +const FEATURE_FLAGS_SECTION = By.css('div#main div#feature-flags') +const FEATURE_FLAGS_TABLE = By.css('div#main div#feature-flags div#ff-table-section table') + +const ACCEPT_ENABLE_EXPERIMENTAL_FEATURE_FLAG = By.css('p#ff-exp-ack-supported') +const CONFIRM_ENABLE_EXPERIMENTAL_FEATURE_FLAG = By.css('button#ff-exp-confirm') + + +module.exports = class FeatureFlagsAdminTab extends AdminTab { + async isLoaded () { + await this.waitForDisplayed(FEATURE_FLAGS_SECTION) + } + + async getAll() { + await this.ensureSectionIsVisible(FEATURE_FLAGS_SECTION) + try + { + return this.getTable(FEATURE_FLAGS_TABLE, 4) + } catch (NoSuchElement) { + return Promise.resolve([]) + } + } + + async enable(name, isExperimental = false) { + let state = await this.getState(name) + if (!await state.isSelected()) { + await this.driver.findElement(this.getParentCheckboxLocator(name)).click() + if (isExperimental) { + await delay(1000) + const dialog = await this.driver.wait( + until.elementLocated(By.css('dialog#ff-exp-dialog[open]')), + 10000 // 10 seconds timeout + ) + await dialog.findElement(ACCEPT_ENABLE_EXPERIMENTAL_FEATURE_FLAG).click() + await dialog.findElement(CONFIRM_ENABLE_EXPERIMENTAL_FEATURE_FLAG).click() + return delay(1000) + }else { + return Promise.resolve() + } + }else { + return Promise.resolve() + } + } + getCheckboxLocator(name) { + return By.css('div#ff-table-section table input#ff-checkbox-' + name) + } + getParentCheckboxLocator(name) { + return By.css('div#ff-table-section table td#ff-td-' + name) + } + async getState(name) { + return this.driver.findElement(this.getCheckboxLocator(name)) + } + +}