Merge pull request #13866 from rabbitmq/mergify/bp/v4.1.x/pr-13848
Test Management UI with Selenium / selenium (chrome, 1.17.3, 27.3) (push) Waiting to run Details

Add several functions to mgt-api.js for wsr testing with selenium (backport #13848)
This commit is contained in:
Michael Klishin 2025-05-07 21:54:02 +04:00 committed by GitHub
commit 6c4677e1b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 272 additions and 88 deletions

View File

@ -28,14 +28,14 @@ start_other_rabbitmq() {
if [[ "$PROFILES_FOR_OTHER" == *"docker"* ]]; then
start_docker_other_rabbitmq
else
start_local_rabbitmq
start_local_other_rabbitmq
fi
}
stop_other_rabbitmq() {
if [[ "$PROFILES_FOR_OTHER" == *"docker"* ]]; then
kill_container_if_exist "$component"
kill_container_if_exist "${OTHER_RABBITMQ_HOSTNAME}"
else
stop_local_rabbitmq
stop_local_other_rabbitmq
fi
}
@ -44,7 +44,7 @@ save_logs_other_rabbitmq() {
if [[ "$PROFILES_FOR_OTHER" == *"cluster"* ]]; then
docker compose -f $CONF_DIR/rabbitmq/other-compose.yml logs > $LOGS/other-rabbitmq.log
else
save_container_logs "other-rabbitmq"
save_container_logs "${OTHER_RABBITMQ_HOSTNAME}"
fi
fi
}
@ -129,13 +129,15 @@ start_docker_other_rabbitmq() {
print "> RABBITMQ_TEST_DIR: /var/rabbitmq"
docker run \
--rm \
--detach \
--name ${OTHER_RABBITMQ_HOSTNAME} \
--net ${DOCKER_NETWORK} \
-p 5674:5672 \
-p 5673:5671 \
-p 15674:15672 \
-p 15673:15671 \
-p 15675:15675 \
-p 5552:5552 \
-v $CONF_DIR/other-rabbitmq/:/etc/rabbitmq \
-v $CONF_DIR/other-rabbitmq/imports:/var/rabbitmq/imports \
-v ${TEST_DIR}:/config \

View File

@ -188,6 +188,7 @@ start_docker_rabbitmq() {
-p 5671:5671 \
-p 15672:15672 \
-p 15671:15671 \
-p 5551:5551 \
-v $CONF_DIR/rabbitmq/:/etc/rabbitmq \
-v $CONF_DIR/rabbitmq/imports:/var/rabbitmq/imports \
-v ${TEST_DIR}:/config \

View File

@ -355,8 +355,8 @@ _test() {
print "> FAKEPORTAL_URL: ${FAKEPORTAL_URL}"
mocha_test_tag=($(md5sum $SELENIUM_ROOT_FOLDER/package.json))
print "> OAUTH_NODE_EXTRA_CA_CERTS: ${OAUTH_NODE_EXTRA_CA_CERTS}"
MOUNT_NODE_EXTRA_CA_CERTS=${TEST_DIR}/${OAUTH_NODE_EXTRA_CA_CERTS}
generate_node_extra_ca_cert
MOUNT_NODE_EXTRA_CA_CERTS=${CONF_DIR}/node_ca_certs.pem
print "> MOUNT_NODE_EXTRA_CA_CERTS: ${MOUNT_NODE_EXTRA_CA_CERTS}"
docker run \
@ -417,7 +417,7 @@ other_profiles_with_local_or_docker() {
fi
}
generate_env_file() {
begin "Generating env file from profiles ${PROFILES} ..."
begin "Generating env file from profiles: [${PROFILES}] ..."
mkdir -p $CONF_DIR
${BIN_DIR}/gen-env-file "${PROFILES}" $TEST_CONFIG_DIR ${ENV_FILE}.tmp
grep -v '^#' ${ENV_FILE}.tmp > $ENV_FILE
@ -425,7 +425,7 @@ generate_env_file() {
end "Finished generating env file."
}
generate_other_env_file() {
begin "Generating other env file from profiles ${PROFILES_FOR_OTHER} "
begin "Generating other env file from profiles: [${PROFILES_FOR_OTHER}] "
mkdir -p $CONF_DIR
${BIN_DIR}/gen-env-file "${PROFILES_FOR_OTHER}" $TEST_CONFIG_DIR ${OTHER_ENV_FILE}.tmp
grep -v '^#' ${OTHER_ENV_FILE}.tmp > $OTHER_ENV_FILE
@ -674,7 +674,7 @@ test_local() {
export SELENIUM_POLLING=${SELENIUM_POLLING:-500}
generate_node_extra_ca_cert
MOUNT_NODE_EXTRA_CA_CERTS=${RABBITMQ_CERTS}/node_ca_certs.pem
MOUNT_NODE_EXTRA_CA_CERTS=${CONF_DIR}/node_ca_certs.pem
print "> SELENIUM_TIMEOUT: ${SELENIUM_TIMEOUT}"
print "> SELENIUM_POLLING: ${SELENIUM_POLLING}"
@ -738,14 +738,16 @@ save_components_logs() {
end "Finished saving logs"
}
generate_node_extra_ca_cert() {
echo "Generating $RABBITMQ_CERTS/node_ca_certs.pem ..."
rm -f $RABBITMQ_CERTS/node_ca_certs.pem
echo "Generating ${CONF_DIR}/node_ca_certs.pem ..."
rm -f ${CONF_DIR}/node_ca_certs.pem
env | while IFS= read -r line; do
value=${line#*=}
name=${line%%=*}
if [[ $name == *NODE_EXTRA_CA_CERTS ]]
then
cat ${TEST_DIR}/${value} >> $RABBITMQ_CERTS/node_ca_certs.pem
echo "Adding ${TEST_DIR}/${value} to ${CONF_DIR}/node_ca_certs.pem ..."
cat ${TEST_DIR}/${value} >> ${CONF_DIR}/node_ca_certs.pem
fi
done
}

View File

@ -1,5 +1,6 @@
var http = require('http'),
httpProxy = require('http-proxy');
const {log, error} = require('./utils.js')
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const rabbitmq_url = process.env.RABBITMQ_URL || 'http://0.0.0.0:15672/';
@ -14,7 +15,7 @@ const port = process.env.PORT;
var proxy = httpProxy.createProxyServer({});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
console.log("proxing " + req.url)
log("proxing " + req.url)
if (req.url.endsWith("bootstrap.js")) {
proxyReq.setHeader('Authorization', 'Bearer ' + access_token(client_id, client_secret));
}
@ -30,7 +31,7 @@ var server = http.createServer(function(req, res) {
target: rabbitmq_url
});
});
console.log("fakeproxy listening on port " + port + ". RABBITMQ_URL=" + rabbitmq_url)
log("fakeproxy listening on port " + port + ". RABBITMQ_URL=" + rabbitmq_url)
server.listen(port);
@ -51,18 +52,19 @@ function access_token(id, secret) {
'&token_format=jwt' +
'&response_type=token';
console.debug("Sending " + url + " with params "+ params);
log("Sending " + url + " with params "+ params);
req.open('POST', url, false);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setRequestHeader('Accept', 'application/json');
req.send(params);
console.log("Ret " + req.status)
log("Ret " + req.status)
if (req.status == 200) {
const token = JSON.parse(req.responseText).access_token;
console.log("Token => " + token)
log("Token => " + token)
return token;
} else {
error("Failed to get access token due to " + req.responseText)
throw new Error(req.status + " : " + req.responseText);
}
}

View File

@ -1,6 +1,8 @@
var container = require('rhea') // https://github.com/amqp/rhea
var fs = require('fs');
var path = require('path');
const {log, error} = require('./utils.js')
var connectionOptions = getConnectionOptions()
function getAmqpConnectionOptions() {
@ -28,7 +30,7 @@ function getAmqpsConnectionOptions() {
}
function getConnectionOptions() {
let scheme = process.env.RABBITMQ_AMQP_SCHEME || 'amqp'
console.log("Using AMQP protocol: " + scheme)
log("Using AMQP protocol: " + scheme)
switch(scheme){
case "amqp":
return getAmqpConnectionOptions()

View File

@ -1,5 +1,5 @@
const assert = require('assert')
const { tokenFor, openIdConfiguration } = require('../utils')
const { log, tokenFor, openIdConfiguration } = require('../utils')
const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend')
const { open: openAmqp, once: onceAmqp, on: onAmqp, close: closeAmqp } = require('../amqp')
@ -48,11 +48,11 @@ describe('Having AMQP 1.0 protocol enabled and the following auth_backends: ' +
let oauthProviderUrl = process.env.OAUTH_PROVIDER_URL
let oauthClientId = process.env.OAUTH_CLIENT_ID
let oauthClientSecret = process.env.OAUTH_CLIENT_SECRET
console.log("oauthProviderUrl : " + oauthProviderUrl)
log("oauthProviderUrl : " + oauthProviderUrl)
let openIdConfig = openIdConfiguration(oauthProviderUrl)
console.log("Obtained token_endpoint : " + openIdConfig.token_endpoint)
log("Obtained token_endpoint : " + openIdConfig.token_endpoint)
password = tokenFor(oauthClientId, oauthClientSecret, openIdConfig.token_endpoint)
console.log("Obtained access token : " + password)
log("Obtained access token : " + password)
}
})
@ -78,7 +78,7 @@ describe('Having AMQP 1.0 protocol enabled and the following auth_backends: ' +
closeAmqp(amqp.connection)
}
} catch (error) {
console.error("Failed to close amqp10 connection due to " + error);
error("Failed to close amqp10 connection due to " + error);
}
})
})

View File

@ -1,6 +1,6 @@
const fs = require('fs')
const assert = require('assert')
const { tokenFor, openIdConfiguration } = require('../utils')
const { tokenFor, openIdConfiguration, log } = require('../utils')
const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend')
const mqtt = require('mqtt');
@ -45,9 +45,9 @@ describe('Having MQTT protocol enbled and the following auth_backends: ' + backe
let oauthClientId = process.env.OAUTH_CLIENT_ID
let oauthClientSecret = process.env.OAUTH_CLIENT_SECRET
let openIdConfig = openIdConfiguration(oauthProviderUrl)
console.log("Obtained token_endpoint : " + openIdConfig.token_endpoint)
log("Obtained token_endpoint : " + openIdConfig.token_endpoint)
password = tokenFor(oauthClientId, oauthClientSecret, openIdConfig.token_endpoint)
console.log("Obtained access token : " + password)
log("Obtained access token : " + password)
}
mqttOptions = {
clientId: client_id,

View File

@ -1,7 +1,7 @@
const { By, Key, until, Builder } = require('selenium-webdriver')
require('chromedriver')
const assert = require('assert')
const { buildDriver, goToHome, captureScreensFor, teardown, doWhile } = require('../utils')
const { buildDriver, goToHome, captureScreensFor, teardown, doWhile, log } = require('../utils')
const LoginPage = require('../pageobjects/LoginPage')
const OverviewPage = require('../pageobjects/OverviewPage')
@ -56,7 +56,6 @@ describe('Exchange management', function () {
["other", "amq.topic", "topic"]
]
console.log("e :" + actual_table)
assert.deepEqual(actual_table, expected_table)
})

View File

@ -1,4 +1,5 @@
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const { escapeCss } = require('selenium-webdriver')
const {log, error} = require('./utils.js')
const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL || 'http://localhost:15672/')
@ -20,10 +21,56 @@ module.exports = {
return baseUrl
},
geOtherManagementUrl: () => {
getOtherManagementUrl: () => {
return otherBaseUrl
},
basicAuthorization: (username, password) => {
return "Basic " + btoa(username + ":" + password)
},
publish: (url, authorization, vhost, exchange, routingKey, payload) => {
const req = new XMLHttpRequest()
let body = {
"properties" : {},
"routing_key" : routingKey,
"payload" : payload,
"payload_encoding" : "string"
}
log("Publish message to vhost " + vhost + " with exchnage " + exchange + " : " + JSON.stringify(body))
let finalUrl = url + "/api/exchanges/" + encodeURIComponent(vhost) + "/" +
encodeURIComponent(exchange) + "/publish"
req.open('POST', finalUrl, false)
req.setRequestHeader("Authorization", authorization)
req.setRequestHeader('Content-Type', 'application/json')
req.send(JSON.stringify(body))
if (req.status == 200 || req.status == 204 || req.status == 201) {
log("Succesfully published message")
return
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
getNodes: (url) => {
log("Getting rabbitmq nodes ...")
const req = new XMLHttpRequest()
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
let finalUrl = url + "/api/nodes?columns=name"
req.open('GET', finalUrl, false)
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
req.send()
if (req.status == 200 || req.status == 204 || req.status == 201) {
log("Succesfully got nodes ")
return JSON.parse(req.responseText)
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
setPolicy: (url, vhost, name, pattern, definition, appliedTo = "queues") => {
let policy = {
"pattern": pattern,
@ -90,6 +137,27 @@ module.exports = {
throw new Error(req.responseText)
}
},
grantPermissions: (url, vhost, user, permissions) => {
log("Granting permissions [" + JSON.stringify(permissions) +
"] for user " + user + " on vhost " + vhost + " on " + url)
const req = new XMLHttpRequest()
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
let finalUrl = url + "/api/permissions/" + encodeURIComponent(vhost) + "/"
+ encodeURIComponent(user)
req.open('PUT', finalUrl, false)
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
req.setRequestHeader('Content-Type', 'application/json')
req.send(JSON.stringify(permissions))
if (req.status == 200 || req.status == 204 || req.status == 201) {
log("Succesfully granted permissions")
return
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
deleteVhost: (url, vhost) => {
log("Deleting vhost " + vhost)
const req = new XMLHttpRequest()
@ -106,7 +174,68 @@ module.exports = {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
getQueue: (url, name, vhost) => {
log("Getting queue " + name + " on vhost " + vhost)
const req = new XMLHttpRequest()
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/" +
encodeURIComponent(name)
req.open('GET', finalUrl, false)
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
req.send()
if (req.status == 200 || req.status == 204 || req.status == 201) {
log("Succesfully got queue ")
return JSON.parse(req.responseText)
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
createQueue: (url, name, vhost, queueType = "quorum") => {
log("Create queue " + JSON.stringify(name)
+ " in vhost " + vhost + " on " + url)
const req = new XMLHttpRequest()
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/"
+ encodeURIComponent(name)
req.open('PUT', finalUrl, false)
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
req.setRequestHeader('Content-Type', 'application/json')
let payload = {
"durable": true,
"arguments":{
"x-queue-type" : queueType
}
}
req.send(JSON.stringify(payload))
if (req.status == 200 || req.status == 204 || req.status == 201) {
log("Succesfully created queue " + name)
return
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
},
deleteQueue: (url, name, vhost) => {
log("Deleting queue " + name + " on vhost " + vhost)
const req = new XMLHttpRequest()
let base64Credentials = btoa('administrator-only' + ":" + 'guest')
let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/"
+ encodeURIComponent(name)
req.open('DELETE', finalUrl, false)
req.setRequestHeader("Authorization", "Basic " + base64Credentials)
req.send()
if (req.status == 200 || req.status == 204) {
log("Succesfully deleted queue " + vhost)
return
}else {
error("status:" + req.status + " : " + req.responseText)
throw new Error(req.responseText)
}
}
}

View File

@ -11,6 +11,7 @@ describe('A user with a JWT token', function () {
let captureScreen
let token
let fakePortal
let driver
before(async function () {
driver = buildDriver()

View File

@ -11,6 +11,7 @@ describe('An user with administrator tag', function () {
let idpLogin
let overview
let captureScreen
var driver
before(async function () {
driver = buildDriver()

View File

@ -8,6 +8,7 @@ const SSOHomePage = require('../../pageobjects/SSOHomePage')
describe('A user which accesses any protected URL without a session', function () {
let homePage
let captureScreen
let driver
before(async function () {
driver = buildDriver()

View File

@ -11,6 +11,7 @@ describe('When a logged in user', function () {
let homePage
let captureScreen
let idpLogin
let driver
before(async function () {
driver = buildDriver()

View File

@ -13,6 +13,7 @@ describe('Once user is logged in', function () {
let idpLogin
let overview
let captureScreen
let driver
this.timeout(45000) // hard-coded to 25secs because this test requires 35sec to run
before(async function () {

View File

@ -1,7 +1,7 @@
const { By, Key, until, Builder } = require('selenium-webdriver')
require('chromedriver')
const assert = require('assert')
const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage } = require('../../utils')
const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage, delay } = require('../../utils')
const SSOHomePage = require('../../pageobjects/SSOHomePage')
const OverviewPage = require('../../pageobjects/OverviewPage')
@ -11,6 +11,7 @@ describe('An user without management tag', function () {
let idpLogin
let overview
let captureScreen
let driver
before(async function () {
driver = buildDriver()
@ -46,7 +47,7 @@ describe('An user without management tag', function () {
})
it('should get redirected to home page again without error message', async function(){
await driver.sleep(250)
await delay(250)
const visible = await homePage.isWarningVisible()
assert.ok(!visible)
})

View File

@ -28,7 +28,7 @@ module.exports = class BasePage {
interactionDelay
constructor (webdriver) {
this.driver = webdriver
this.driver = webdriver.driver
this.timeout = parseInt(process.env.SELENIUM_TIMEOUT) || 1000 // max time waiting to locate an element. Should be less that test timeout
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)
@ -50,13 +50,17 @@ module.exports = class BasePage {
return this.selectOption(SELECT_REFRESH, option)
}
async selectRefreshOptionByValue(option) {
return this.selectOptionByValue(SELECT_REFRESH, option)
}
async waitForOverviewTab() {
await this.driver.sleep(250)
return this.waitForDisplayed(OVERVIEW_TAB)
}
async clickOnOverviewTab () {
return this.click(CONNECTIONS_TAB)
return this.click(OVERVIEW_TAB)
}
async clickOnConnectionsTab () {
@ -130,7 +134,6 @@ module.exports = class BasePage {
const select = await new Select(selectable)
return select.selectByValue(value)
}
async getSelectableVhosts() {
const table_model = await this.getSelectableOptions(SELECT_VHOSTS)
let new_table_model = []
@ -139,9 +142,11 @@ module.exports = class BasePage {
}
return new_table_model
}
async selectVhost(vhost) {
let selectable = await this.waitForDisplayed(SELECT_VHOSTS)
const select = await new Select(selectable)
return select.selectByValue(vhost)
}
async getTable(tableLocator, firstNColumns, rowClass) {
const table = await this.waitForDisplayed(tableLocator)
const rows = await table.findElements(rowClass == undefined ?
@ -166,16 +171,7 @@ module.exports = class BasePage {
} catch(e) {
return Promise.resolve(false)
}
/*
let element = await driver.findElement(FORM_POPUP)
return this.driver.wait(until.elementIsVisible(element), this.timeout / 2,
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
this.polling / 2).then(function onWarningVisible(e) {
return Promise.resolve(true)
}, function onError(e) {
return Promise.resolve(false)
})
*/
}
async isPopupWarningNotDisplayed() {
@ -199,7 +195,7 @@ module.exports = class BasePage {
}
}
async getPopupWarning() {
let element = await driver.findElement(FORM_POPUP_WARNING)
let element = await this.driver.findElement(FORM_POPUP_WARNING)
return this.driver.wait(until.elementIsVisible(element), this.timeout,
'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element,
this.polling).getText().then((value) => value.substring(0, value.search('\n\nClose')))
@ -363,9 +359,6 @@ module.exports = class BasePage {
await this.driver.sleep(250)
return alert.accept();
}
log(message) {
console.log(new Date() + " " + message)
}
capture () {
this.driver.takeScreenshot().then(

View File

@ -19,7 +19,7 @@ module.exports = class LimitsAdminTab extends AdminTab {
await this.click(VIRTUAL_HOST_LIMITS_SECTION)
try
{
return driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS)
return this.driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS)
} catch (NoSuchElement) {
return Promise.resolve([])
}
@ -28,7 +28,7 @@ module.exports = class LimitsAdminTab extends AdminTab {
await this.click(USER_LIMITS_SECTION)
try
{
return driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS)
return this.driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS)
} catch (NoSuchElement) {
return Promise.resolve([])
}

View File

@ -36,7 +36,7 @@ module.exports = class LoginPage extends BasePage {
async getWarnings() {
try
{
return driver.findElements(WARNING)
return this.driver.findElements(WARNING)
} catch (NoSuchElement) {
return Promise.resolve([])
}

View File

@ -17,7 +17,7 @@ module.exports = class QueuePage extends BasePage {
}
async ensureDeleteQueueSectionIsVisible() {
await this.click(DELETE_SECTION)
return driver.findElement(DELETE_SECTION).isDisplayed()
return this.driver.findElement(DELETE_SECTION).isDisplayed()
}
async deleteQueue() {
await this.click(DELETE_BUTTON)

View File

@ -31,11 +31,11 @@ module.exports = class QueuesAndStreamsPage extends BasePage {
}
async ensureAddQueueSectionIsVisible() {
await this.click(ADD_NEW_QUEUE_SECTION)
return driver.findElement(ADD_NEW_QUEUE_SECTION).isDisplayed()
return this.driver.findElement(ADD_NEW_QUEUE_SECTION).isDisplayed()
}
async ensureAllQueuesSectionIsVisible() {
await this.click(PAGING_SECTION)
return driver.findElement(PAGING_SECTION).isDisplayed()
return this.driver.findElement(PAGING_SECTION).isDisplayed()
}
async fillInAddNewQueue(queueDetails) {
await this.selectOptionByValue(FORM_QUEUE_TYPE, queueDetails.type)

View File

@ -110,7 +110,7 @@ module.exports = class SSOHomePage extends BasePage {
async getWarnings() {
try
{
return driver.findElements(WARNING)
return this.driver.findElements(WARNING)
} catch (NoSuchElement) {
return Promise.resolve([])
}

View File

@ -17,7 +17,7 @@ module.exports = class StreamPage extends BasePage {
}
async ensureDeleteQueueSectionIsVisible() {
await this.click(DELETE_SECTION)
return driver.findElement(DELETE_SECTION).isDisplayed()
return this.driver.findElement(DELETE_SECTION).isDisplayed()
}
async deleteStream() {
await this.click(DELETE_BUTTON)

View File

@ -17,6 +17,7 @@ const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost'
const seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444'
const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens'
const profiles = process.env.PROFILES || ''
const debug = process.env.SELENIUM_DEBUG || false
function randomly_pick_baseurl(baseUrl) {
urls = baseUrl.split(",")
@ -34,7 +35,7 @@ class CaptureScreenshot {
}
async shot (name) {
const image = await driver.takeScreenshot()
const image = await this.driver.takeScreenshot()
const screenshotsSubDir = path.join(screenshotsDir, this.test)
if (!fs.existsSync(screenshotsSubDir)) {
await fsp.mkdir(screenshotsSubDir)
@ -46,7 +47,7 @@ class CaptureScreenshot {
module.exports = {
log: (message) => {
console.log(new Date() + " " + message)
if (debug) console.log(new Date() + " " + message)
},
error: (message) => {
console.error(new Date() + " " + message)
@ -55,7 +56,7 @@ module.exports = {
return profiles.includes(profile)
},
buildDriver: (caps) => {
buildDriver: (url = baseUrl) => {
builder = new Builder()
if (!runLocal) {
builder = builder.usingServer(seleniumUrl)
@ -86,15 +87,23 @@ module.exports = {
"profile.password_manager_leak_detection=false"
]
});
driver = builder
let driver = builder
.forBrowser('chrome')
//.setChromeOptions(options.excludeSwitches("disable-popup-blocking", "enable-automation"))
.withCapabilities(chromeCapabilities)
.build()
driver.manage().setTimeouts( { pageLoad: 35000 } )
return driver
return {
"driver": driver,
"baseUrl": url
}
},
updateDriver: (d, url) => {
return {
"driver" : d.driver,
"baseUrl" : url
}
},
getURLForProtocol: (protocol) => {
switch(protocol) {
@ -103,20 +112,21 @@ module.exports = {
}
},
goToHome: (driver) => {
return driver.get(baseUrl)
goToHome: (d) => {
module.exports.log("goToHome on " + d.baseUrl)
return d.driver.get(d.baseUrl)
},
goToLogin: (driver, token) => {
return driver.get(baseUrl + '#/login?access_token=' + token)
goToLogin: (d, token) => {
return d.driver.get(d.baseUrl + '#/login?access_token=' + token)
},
goToExchanges: (driver) => {
return driver.get(baseUrl + '#/exchanges')
goToExchanges: (d) => {
return d.driver.get(d.baseUrl + '#/exchanges')
},
goTo: (driver, address) => {
return driver.get(address)
goTo: (d, address) => {
return d.get(address)
},
delay: async (msec, ref) => {
@ -125,8 +135,8 @@ module.exports = {
})
},
captureScreensFor: (driver, test) => {
return new CaptureScreenshot(driver, require('path').basename(test))
captureScreensFor: (d, test) => {
return new CaptureScreenshot(d.driver, require('path').basename(test))
},
doWhile: async (doCallback, booleanCallback, delayMs = 1000, message = "doWhile failed") => {
@ -135,16 +145,45 @@ module.exports = {
let ret
do {
try {
//console.log("Calling doCallback (attempts:" + attempts + ") ... ")
module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ")
ret = await doCallback()
//console.log("Calling booleanCallback (attempts:" + attempts + ") with arg " + ret + " ... ")
module.exports.log("Calling booleanCallback (attempts:" + attempts
+ ") with arg " + JSON.stringify(ret) + " ... ")
done = booleanCallback(ret)
}catch(error) {
console.log("Caught " + error + " on doWhile callback...")
module.exports.error("Caught " + error + " on doWhile callback...")
}finally {
if (!done) {
//console.log("Waiting until next attempt")
module.exports.log("Waiting until next attempt")
await module.exports.delay(delayMs)
}
}
attempts--
} while (attempts > 0 && !done)
if (!done) {
throw new Error(message)
}else {
return ret
}
},
retry: async (doCallback, booleanCallback, delayMs = 1000, message = "retry failed") => {
let done = false
let attempts = 10
let ret
do {
try {
module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ")
ret = doCallback()
module.exports.log("Calling booleanCallback (attempts:" + attempts
+ ") with arg " + JSON.stringify(ret) + " ... ")
done = booleanCallback(ret)
}catch(error) {
module.exports.error("Caught " + error + " on doWhile callback...")
}finally {
if (!done) {
module.exports.log("Waiting until next attempt")
await module.exports.delay(delayMs)
}
}
@ -157,7 +196,7 @@ module.exports = {
}
},
idpLoginPage: (driver, preferredIdp) => {
idpLoginPage: (d, preferredIdp) => {
if (!preferredIdp) {
if (process.env.PROFILES.includes("uaa")) {
preferredIdp = "uaa"
@ -168,8 +207,8 @@ module.exports = {
}
}
switch(preferredIdp) {
case "uaa": return new UAALoginPage(driver)
case "keycloak": return new KeycloakLoginPage(driver)
case "uaa": return new UAALoginPage(d)
case "keycloak": return new KeycloakLoginPage(d)
default: new Error("Unsupported ipd " + preferredIdp)
}
},
@ -179,7 +218,7 @@ module.exports = {
req.send()
if (req.status == 200) return JSON.parse(req.responseText)
else {
console.error(req.responseText)
module.exports.error(req.responseText)
throw new Error(req.responseText)
}
},
@ -198,7 +237,7 @@ module.exports = {
req.send(params)
if (req.status == 200) return JSON.parse(req.responseText).access_token
else {
console.error(req.responseText)
module.exports.error(req.responseText)
throw new Error(req.responseText)
}
},
@ -212,10 +251,11 @@ module.exports = {
}
},
teardown: async (driver, test, captureScreen = null) => {
teardown: async (d, test, captureScreen = null) => {
driver = d.driver
driver.manage().logs().get(logging.Type.BROWSER).then(function(entries) {
entries.forEach(function(entry) {
console.log('[%s] %s', entry.level.name, entry.message);
module.exports.log('[%s] %s', entry.level.name, entry.message);
})
})
if (test.currentTest) {
@ -227,6 +267,14 @@ module.exports = {
}
}
await driver.quit()
},
findTableRow: (table, booleanCallback) => {
if (!table) return false
let i = 0
while (i < table.length && !booleanCallback(table[i])) i++;
return i < table.length ? table[i] : undefined
}
}