Skip to content

Commit 6f94956

Browse files
Merge pull request #14446 from rabbitmq/test-feature-flags-in-management-ui
New Selenium suite for testing feature flags in management UI in v4.1.x
2 parents e8d3116 + 02903cf commit 6f94956

File tree

8 files changed

+147
-6
lines changed

8 files changed

+147
-6
lines changed

deps/rabbitmq_management/priv/www/js/tmpl/feature-flags.ejs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</p>
2121
<button id="ff-enable-all-button" onclick='enable_all_stable_feature_flags(this);'>Enable all stable feature flags</button>
2222
</div>
23-
<div class="section">
23+
<div class="section" id="feature-flags">
2424
<h2>Feature Flags</h2>
2525
<div class="hider">
2626
<%= filter_ui(nonreq_feature_flags) %>
@@ -301,7 +301,7 @@ function enable_feature_flag(checkbox, feature_flag) {
301301
</svg>
302302
<% } %>
303303
</td>
304-
<td class="c ff-stability-<%= feature_flag.stability %> ff-state-<%= feature_flag.state %>">
304+
<td id="ff-td-<%= feature_flag.name %>" class="c ff-stability-<%= feature_flag.stability %> ff-state-<%= feature_flag.state %>">
305305
<input id="ff-checkbox-<%= feature_flag.name %>" type="checkbox" class="toggle"
306306
<% if (feature_flag.state == 'enabled') { %>
307307
checked disabled
@@ -349,7 +349,7 @@ function enable_feature_flag(checkbox, feature_flag) {
349349
Therefore, upgrades to a later version of RabbitMQ with this feature flag
350350
enabled are supported.
351351
</p>
352-
<p>
352+
<p id="ff-exp-ack-supported">
353353
<input id="ff-exp-ack-supported-checkbox" type="checkbox"/>
354354
<label for="ff-exp-ack-supported-checkbox">I understand that this feature is experimental and should be tested first.</label>
355355
</p>

selenium/full-suite-management-ui

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ mgt/exchanges.sh
2222
mgt/limits.sh
2323
mgt/mgt-only-exchanges.sh
2424
mgt/queuesAndStreams.sh
25+
mgt/feature-flags.sh

selenium/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"author": "",
1313
"license": "ISC",
1414
"dependencies": {
15-
"chromedriver": "^137.0",
15+
"chromedriver": "^139.0",
1616
"ejs": "^3.1.8",
1717
"express": "^4.18.2",
1818
"geckodriver": "^3.0.2",

selenium/short-suite-management-ui

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ mgt/queuesAndStreams.sh
99
mgt/limits.sh
1010
mgt/amqp10-connections.sh
1111
mgt/mqtt-connections.sh
12+
mgt/feature-flags.sh
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4+
5+
TEST_CASES_PATH=/feature-flags
6+
TEST_CONFIG_PATH=/basic-auth
7+
8+
source $SCRIPT/../../bin/suite_template $@
9+
run
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const { By, Key, until, Builder } = require('selenium-webdriver')
2+
require('chromedriver')
3+
const assert = require('assert')
4+
const { buildDriver, goToHome, captureScreensFor, teardown, findTableRow, doUntil } = require('../utils')
5+
6+
const LoginPage = require('../pageobjects/LoginPage')
7+
const OverviewPage = require('../pageobjects/OverviewPage')
8+
const AdminTab = require('../pageobjects/AdminTab')
9+
const FeatureFlagsAdminTab = require('../pageobjects/FeatureFlagsAdminTab')
10+
11+
describe('Feature flags in Admin tab', function () {
12+
let login
13+
let overview
14+
let ffTab
15+
let captureScreen
16+
17+
before(async function () {
18+
driver = buildDriver()
19+
await goToHome(driver)
20+
login = new LoginPage(driver)
21+
overview = new OverviewPage(driver)
22+
adminTab = new AdminTab(driver)
23+
ffTab = new FeatureFlagsAdminTab(driver)
24+
captureScreen = captureScreensFor(driver, __filename)
25+
26+
await login.login('guest', 'guest')
27+
if (!await overview.isLoaded()) {
28+
throw new Error('Failed to login')
29+
}
30+
await overview.selectRefreshOption("Do not refresh")
31+
})
32+
33+
it('it has at least one feature flag', async function () {
34+
await overview.clickOnAdminTab()
35+
await adminTab.clickOnFeatureFlags()
36+
let ffTable = await ffTab.getAll()
37+
assert(ffTable.length > 0)
38+
})
39+
it('it has khepri_db feature flag', async function () {
40+
await overview.clickOnAdminTab()
41+
await adminTab.clickOnFeatureFlags()
42+
let ffTable = await ffTab.getAll()
43+
assert(findTableRow(ffTable, function(row) {
44+
return row[0] === 'khepri_db'
45+
}))
46+
})
47+
it('enable khepri_db feature flag', async function () {
48+
await overview.clickOnAdminTab()
49+
await adminTab.clickOnFeatureFlags()
50+
let prev_state = await ffTab.getState('khepri_db')
51+
assert(!await prev_state.isSelected())
52+
await ffTab.enable('khepri_db')
53+
await doUntil(async function() {
54+
return ffTab.getState('khepri_db')
55+
}, function(state) {
56+
return state.isSelected()
57+
}, 6000)
58+
59+
})
60+
61+
62+
after(async function () {
63+
await teardown(driver, this, captureScreen)
64+
})
65+
})

selenium/test/pageobjects/BasePage.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@ module.exports = class BasePage {
3333
this.polling = parseInt(process.env.SELENIUM_POLLING) || 500 // how frequent selenium searches for an element
3434
this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy)
3535
}
36-
36+
async ensureSectionIsVisible(section) {
37+
let classes = await this.driver.findElement(section).getAttribute("class")
38+
if (classes.search('section-visible') < 0) {
39+
return this.click(section)
40+
} else {
41+
return Promise.resolve(true)
42+
}
43+
}
3744
async goTo(path) {
3845
return driver.get(d.baseUrl + path)
3946
}
@@ -381,7 +388,6 @@ module.exports = class BasePage {
381388

382389
async click (locator) {
383390
if (this.interactionDelay) await this.driver.sleep(this.interactionDelay)
384-
385391
const element = await this.waitForDisplayed(locator)
386392
try {
387393
return element.click()
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const { By, Key, until, Builder } = require('selenium-webdriver')
2+
const { delay } = require('../utils')
3+
4+
const AdminTab = require('./AdminTab')
5+
6+
7+
const FEATURE_FLAGS_SECTION = By.css('div#main div#feature-flags')
8+
const FEATURE_FLAGS_TABLE = By.css('div#main div#feature-flags div#ff-table-section table')
9+
10+
const ACCEPT_ENABLE_EXPERIMENTAL_FEATURE_FLAG = By.css('p#ff-exp-ack-supported')
11+
const CONFIRM_ENABLE_EXPERIMENTAL_FEATURE_FLAG = By.css('button#ff-exp-confirm')
12+
13+
14+
module.exports = class FeatureFlagsAdminTab extends AdminTab {
15+
async isLoaded () {
16+
await this.waitForDisplayed(FEATURE_FLAGS_SECTION)
17+
}
18+
19+
async getAll() {
20+
await this.ensureSectionIsVisible(FEATURE_FLAGS_SECTION)
21+
try
22+
{
23+
return this.getTable(FEATURE_FLAGS_TABLE, 4)
24+
} catch (NoSuchElement) {
25+
return Promise.resolve([])
26+
}
27+
}
28+
29+
async enable(name, isExperimental = false) {
30+
let state = await this.getState(name)
31+
if (!await state.isSelected()) {
32+
await this.driver.findElement(this.getParentCheckboxLocator(name)).click()
33+
if (isExperimental) {
34+
await delay(1000)
35+
const dialog = await this.driver.wait(
36+
until.elementLocated(By.css('dialog#ff-exp-dialog[open]')),
37+
10000 // 10 seconds timeout
38+
)
39+
await dialog.findElement(ACCEPT_ENABLE_EXPERIMENTAL_FEATURE_FLAG).click()
40+
await dialog.findElement(CONFIRM_ENABLE_EXPERIMENTAL_FEATURE_FLAG).click()
41+
return delay(1000)
42+
}else {
43+
return Promise.resolve()
44+
}
45+
}else {
46+
return Promise.resolve()
47+
}
48+
}
49+
getCheckboxLocator(name) {
50+
return By.css('div#ff-table-section table input#ff-checkbox-' + name)
51+
}
52+
getParentCheckboxLocator(name) {
53+
return By.css('div#ff-table-section table td#ff-td-' + name)
54+
}
55+
async getState(name) {
56+
return this.driver.findElement(this.getCheckboxLocator(name))
57+
}
58+
59+
}

0 commit comments

Comments
 (0)