Skip to content

Commit 8cbd7e6

Browse files
Merge pull request #13838 from rabbitmq/selenium-select-columns-for-virtualhosts
Test management ui selection of vhost's tags columns
2 parents 6c75497 + fb02466 commit 8cbd7e6

File tree

10 files changed

+407
-22
lines changed

10 files changed

+407
-22
lines changed

deps/rabbitmq_management/priv/www/js/tmpl/popup.ejs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
<%= text %>
33
<br/>
44
<br/>
5-
<span>Close</span>
5+
<span id="close">Close</span>
66
</div>

deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<h1>Virtual Hosts</h1>
22

3-
<div class="section">
3+
<div class="section" id="vhosts">
44
<h2>All virtual hosts</h2>
55
<div class="hider">
66
<%= filter_ui(vhosts) %>
77
<div class="updatable">
88
<% if (vhosts.length > 0) { %>
9-
<table class="list">
9+
<table class="list" >
1010
<thead>
1111
<tr>
1212
<%= group_heading('vhosts', 'Overview', [true, true, true]) %>

selenium/.node-xmlhttprequest-sync-88011

Whitespace-only changes.

selenium/test/exchanges/management.js

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { By, Key, until, Builder } = require('selenium-webdriver')
22
require('chromedriver')
33
const assert = require('assert')
4-
const { buildDriver, goToHome, captureScreensFor, teardown, delay } = require('../utils')
4+
const { buildDriver, goToHome, captureScreensFor, teardown, doWhile } = require('../utils')
55

66
const LoginPage = require('../pageobjects/LoginPage')
77
const OverviewPage = require('../pageobjects/OverviewPage')
@@ -66,6 +66,41 @@ describe('Exchange management', function () {
6666
assert.equal("amq.fanout", await exchange.getName())
6767
})
6868

69+
it('queue selectable columns', async function () {
70+
await overview.clickOnOverviewTab()
71+
await overview.clickOnExchangesTab()
72+
await doWhile(async function() { return exchanges.getExchangesTable() },
73+
function(table) {
74+
return table.length > 0
75+
})
76+
77+
await exchanges.clickOnSelectTableColumns()
78+
let table = await exchanges.getSelectableTableColumns()
79+
80+
assert.equal(2, table.length)
81+
let overviewGroup = {
82+
"name" : "Overview:",
83+
"columns": [
84+
{"name:":"Type","id":"checkbox-exchanges-type"},
85+
{"name:":"Features (with policy)","id":"checkbox-exchanges-features"},
86+
{"name:":"Features (no policy)","id":"checkbox-exchanges-features_no_policy"},
87+
{"name:":"Policy","id":"checkbox-exchanges-policy"}
88+
]
89+
}
90+
assert.equal(JSON.stringify(table[0]), JSON.stringify(overviewGroup))
91+
92+
let messageRatesGroup = {
93+
"name" : "Message rates:",
94+
"columns": [
95+
{"name:":"rate in","id":"checkbox-exchanges-rate-in"},
96+
{"name:":"rate out","id":"checkbox-exchanges-rate-out"}
97+
]
98+
}
99+
assert.equal(JSON.stringify(table[1]), JSON.stringify(messageRatesGroup))
100+
101+
})
102+
103+
69104
after(async function () {
70105
await teardown(driver, this, captureScreen)
71106
})

selenium/test/mgt-api.js

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
2+
const {log, error} = require('./utils.js')
3+
4+
const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL || 'http://localhost:15672/')
5+
const otherBaseUrl = randomly_pick_baseurl(process.env.OTHER_RABBITMQ_URL || 'http://localhost:15675/')
6+
const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost'
7+
const otherHostname = process.env.OTHER_RABBITMQ_HOSTNAME || 'localhost'
8+
9+
function randomly_pick_baseurl (baseUrl) {
10+
urls = baseUrl.split(",")
11+
return urls[getRandomInt(urls.length)]
12+
}
13+
function getRandomInt(max) {
14+
return Math.floor(Math.random() * max)
15+
}
16+
17+
module.exports = {
18+
19+
getManagementUrl: () => {
20+
return baseUrl
21+
},
22+
23+
geOtherManagementUrl: () => {
24+
return otherBaseUrl
25+
},
26+
27+
setPolicy: (url, vhost, name, pattern, definition, appliedTo = "queues") => {
28+
let policy = {
29+
"pattern": pattern,
30+
"apply-to": appliedTo,
31+
"definition": definition
32+
}
33+
log("Setting policy " + JSON.stringify(policy)
34+
+ " with name " + name + " for vhost " + vhost + " on "+ url)
35+
const req = new XMLHttpRequest()
36+
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
37+
let finalUrl = url + "/api/policies/" + encodeURIComponent(vhost) + "/" +
38+
encodeURIComponent(name)
39+
req.open('PUT', finalUrl, false)
40+
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
41+
req.setRequestHeader('Content-Type', 'application/json')
42+
43+
req.send(JSON.stringify(policy))
44+
if (req.status == 200 || req.status == 204 || req.status == 201) {
45+
log("Succesfully set policy " + name)
46+
return
47+
}else {
48+
error("status:" + req.status + " : " + req.responseText)
49+
throw new Error(req.responseText)
50+
}
51+
},
52+
deletePolicy: (url, vhost, name) => {
53+
log("Deleting policy " + name + " on vhost " + vhost)
54+
const req = new XMLHttpRequest()
55+
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
56+
let finalUrl = url + "/api/policies/" + encodeURIComponent(vhost) + "/" +
57+
encodeURIComponent(name)
58+
req.open('DELETE', finalUrl, false)
59+
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
60+
61+
req.send()
62+
if (req.status == 200 || req.status == 204) {
63+
log("Succesfully deleted policy " + name)
64+
return
65+
}else {
66+
error("status:" + req.status + " : " + req.responseText)
67+
throw new Error(req.responseText)
68+
}
69+
},
70+
createVhost: (url, name, description = "", tags = []) => {
71+
let vhost = {
72+
"description": description,
73+
"tags": tags
74+
}
75+
log("Create vhost " + JSON.stringify(vhost)
76+
+ " with name " + name + " on " + url)
77+
const req = new XMLHttpRequest()
78+
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
79+
let finalUrl = url + "/api/vhosts/" + encodeURIComponent(name)
80+
req.open('PUT', finalUrl, false)
81+
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
82+
req.setRequestHeader('Content-Type', 'application/json')
83+
84+
req.send(JSON.stringify(vhost))
85+
if (req.status == 200 || req.status == 204 || req.status == 201) {
86+
log("Succesfully created vhost " + name)
87+
return
88+
}else {
89+
error("status:" + req.status + " : " + req.responseText)
90+
throw new Error(req.responseText)
91+
}
92+
},
93+
deleteVhost: (url, vhost) => {
94+
log("Deleting vhost " + vhost)
95+
const req = new XMLHttpRequest()
96+
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
97+
let finalUrl = url + "/api/vhosts/" + encodeURIComponent(vhost)
98+
req.open('DELETE', finalUrl, false)
99+
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
100+
101+
req.send()
102+
if (req.status == 200 || req.status == 204) {
103+
log("Succesfully deleted vhost " + vhost)
104+
return
105+
}else {
106+
error("status:" + req.status + " : " + req.responseText)
107+
throw new Error(req.responseText)
108+
}
109+
}
110+
111+
112+
}

selenium/test/pageobjects/BasePage.js

+46-7
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@ const EXCHANGES_TAB = By.css('div#menu ul#tabs li#exchanges')
1313
const ADMIN_TAB = By.css('div#menu ul#tabs li#admin')
1414
const STREAM_CONNECTIONS_TAB = By.css('div#menu ul#tabs li#stream-connections')
1515

16-
const FORM_POPUP = By.css('div.form-popup-warn')
17-
const FORM_POPUP_CLOSE_BUTTON = By.css('div.form-popup-warn span')
16+
const FORM_POPUP_WARNING = By.css('div.form-popup-warn')
17+
const FORM_POPUP_WARNING_CLOSE_BUTTON = By.css('div.form-popup-warn span#close')
18+
19+
const FORM_POPUP_OPTIONS = By.css('div.form-popup-options')
20+
const ADD_MINUS_BUTTON = By.css('div#main table.list thead tr th.plus-minus')
21+
const TABLE_COLUMNS_POPUP = By.css('div.form-popup-options table.form')
22+
const FORM_POPUP_OPTIONS_CLOSE_BUTTON = By.css('div.form-popup-options span#close')
1823

1924
module.exports = class BasePage {
2025
driver
@@ -136,6 +141,7 @@ module.exports = class BasePage {
136141
}
137142

138143

144+
139145
async getTable(tableLocator, firstNColumns, rowClass) {
140146
const table = await this.waitForDisplayed(tableLocator)
141147
const rows = await table.findElements(rowClass == undefined ?
@@ -145,15 +151,17 @@ module.exports = class BasePage {
145151
let columns = await row.findElements(By.css('td'))
146152
let table_row = []
147153
for (let column of columns) {
148-
if (table_row.length < firstNColumns) table_row.push(await column.getText())
154+
if (firstNColumns == undefined || table_row.length < firstNColumns) {
155+
table_row.push(await column.getText())
156+
}
149157
}
150158
table_model.push(table_row)
151159
}
152160
return table_model
153161
}
154162
async isPopupWarningDisplayed() {
155163
try {
156-
let element = await driver.findElement(FORM_POPUP)
164+
let element = await driver.findElement(FORM_POPUP_WARNING)
157165
return element.isDisplayed()
158166
} catch(e) {
159167
return Promise.resolve(false)
@@ -171,7 +179,7 @@ module.exports = class BasePage {
171179
}
172180

173181
async isPopupWarningNotDisplayed() {
174-
return this.isElementNotVisible(FORM_POPUP)
182+
return this.isElementNotVisible(FORM_POPUP_WARNING)
175183
}
176184

177185
async isElementNotVisible(locator) {
@@ -191,14 +199,45 @@ module.exports = class BasePage {
191199
}
192200
}
193201
async getPopupWarning() {
194-
let element = await driver.findElement(FORM_POPUP)
202+
let element = await driver.findElement(FORM_POPUP_WARNING)
195203
return this.driver.wait(until.elementIsVisible(element), this.timeout,
196204
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
197205
this.polling).getText().then((value) => value.substring(0, value.search('\n\nClose')))
198206
}
199207
async closePopupWarning() {
200-
return this.click(FORM_POPUP_CLOSE_BUTTON)
208+
return this.click(FORM_POPUP_WARNING_CLOSE_BUTTON)
201209
}
210+
async clickOnSelectTableColumns() {
211+
return this.click(ADD_MINUS_BUTTON)
212+
}
213+
async getSelectableTableColumns() {
214+
const table = await this.waitForDisplayed(TABLE_COLUMNS_POPUP)
215+
const rows = await table.findElements(By.css('tbody tr'))
216+
let table_model = []
217+
for (let i = 1; i < rows.length; i++) { // skip first row
218+
let groupNameLabel = await rows[i].findElement(By.css('th label'))
219+
let groupName = await groupNameLabel.getText()
220+
let columns = await rows[i].findElements(By.css('td label'))
221+
let table_row = []
222+
for (let column of columns) {
223+
let checkbox = await column.findElement(By.css('input'))
224+
table_row.push({"name:" : await column.getText(), "id" : await checkbox.getAttribute("id")})
225+
}
226+
let group = {"name": groupName, "columns": table_row}
227+
table_model.push(group)
228+
}
229+
return table_model
230+
}
231+
async selectTableColumnsById(arrayOfColumnsIds) {
232+
await this.clickOnSelectTableColumns()
233+
const table = await this.waitForDisplayed(TABLE_COLUMNS_POPUP)
234+
for (let id of arrayOfColumnsIds) {
235+
let checkbox = await table.findElement(By.css('tbody tr input#'+id))
236+
await checkbox.click()
237+
}
238+
await this.click(FORM_POPUP_OPTIONS_CLOSE_BUTTON)
239+
}
240+
202241
async isDisplayed(locator) {
203242
try {
204243
let element = await driver.findElement(locator)

selenium/test/pageobjects/VhostsAdminTab.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ const { By, Key, until, Builder } = require('selenium-webdriver')
22

33
const AdminTab = require('./AdminTab')
44

5+
const MAIN_SECTION = By.css('div#main div#vhosts.section')
6+
57
const SELECTED_VHOSTS_ON_RHM = By.css('div#rhs ul li a[href="#/vhosts"]')
68
const FILTER_VHOST = By.css('div#main div.filter input#filter')
79
const CHECKBOX_REGEX = By.css('div#main div.filter input#filter-regex-mode')
810

911
const VHOSTS_TABLE_ROWS = By.css('div#main table.list tbody tr')
12+
const TABLE_SECTION = By.css('div#main div#vhosts.section table.list')
1013

1114
module.exports = class VhostsAdminTab extends AdminTab {
1215
async isLoaded () {
13-
await this.waitForDisplayed(SELECTED_VHOSTS_ON_RHM)
16+
await this.waitForDisplayed(MAIN_SECTION)
1417
}
1518
async searchForVhosts(vhost, regex = false) {
1619
await this.sendKeys(FILTER_VHOST, vhost)
17-
await this.sendKeys(FILTER_VHOST, Key.RETURN)
20+
//await this.sendKeys(FILTER_VHOST, Key.RETURN)
1821
if (regex) {
1922
await this.click(CHECKBOX_REGEX)
2023
}
@@ -28,9 +31,12 @@ module.exports = class VhostsAdminTab extends AdminTab {
2831
const links = await vhost_rows.findElements(By.css("td a"))
2932
for (let link of links) {
3033
let text = await link.getText()
31-
if ( text === "/" ) return link.click()
34+
if ( text === vhost ) return link.click()
3235
}
3336
throw "Vhost " + vhost + " not found"
3437
}
38+
async getVhostsTable(firstNColumns) {
39+
return this.getTable(TABLE_SECTION, firstNColumns)
40+
}
3541

3642
}

0 commit comments

Comments
 (0)