Update frontend tests, add loginpage test

the runner now supports --host, --port, --path, --user and --pass for
icingaweb access and doesn't spawn any servers by itself.

Also a login test has been added. Other tests are removed as they don't
apply anymore.

refs #4491
This commit is contained in:
Jannis Moßhammer 2013-08-23 16:58:26 +02:00
parent b5812fd56c
commit 81b41326cc
21 changed files with 338 additions and 400 deletions

View File

@ -63,7 +63,7 @@ class AuthenticationController extends ActionController
$credentials = new Credentials();
$this->view->form = new LoginForm();
$this->view->form->setRequest($this->_request);
$this->view->title = "Icinga Web Login";
try {
$auth = AuthManager::getInstance(null, array(
'writeSession' => $this->modifiesSession

View File

@ -43,6 +43,7 @@ class LoginForm extends Form
*/
protected function create()
{
$this->setName('login');
$this->addElement(
'text',
'username',

View File

@ -11,7 +11,7 @@
<meta charset="utf-8">
<meta content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<title><?= $this->title ? $this->title : 'Icinga Web'; ?></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

View File

@ -13,17 +13,19 @@
<!-- </form>-->
<!-- </li>-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" id="icinga_app_nav_useraction">
<span id="icinga_app_nav_username">
<?= $this->escape($this->auth()->getUser()->getUsername()); ?>
</span>
<i>{{USER_ICON}}</i>
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<li id="icinga_app_nav_preferences">
<a href="<?= $this->href('/preference'); ?>"><?= $this->translate('Preferences'); ?> </a>
</li>
<li>
<a href="<?= $this->href('/authentication/logout'); ?>"><?= $this->translate('Logout'); ?></a>
<li id="icinga_app_nav_logout">
<a href="<?= $this->href('/authentication/logout'); ?>" title="Logout"><?= $this->translate('Logout'); ?></a>
</li>
</ul>
</li>

View File

@ -1,10 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
require_once dirname(__FILE__). '/../library/Icinga/Application/ApplicationBootstrap.php';
require_once dirname(__FILE__). '/../library/Icinga/Application/Web.php';
use Icinga\Application\Web;
Web::start(@icingaweb_config_path@)->dispatch();

View File

@ -1,61 +0,0 @@
var i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
casper.start("http://localhost:12999/generic.html");
casper.then(function() {
casper.page.evaluate(i2w.setupRequireJs, {icinga: true});
});
casper.then(function() {
this.test.assertTitle("Icinga test page");
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment1.html");
});
});
/*this.waitFor(function() {
return document.querySelectorAll("#icinga-main a") ;
}, */
casper.waitForSelector("div#icinga-main a", onFirstLink);
});
var onFirstLink = function() {
var links = casper.page.evaluate(function() {
return document.querySelectorAll("div#icinga-main a");
});
// assert no reload
this.test.assertTitle("Icinga test page");
this.test.assertUrlMatch(/.*testFragment1.html/);
this.test.assertEquals(links.length, 2);
casper.clickLabel('Fragment 2');
casper.waitForText('Fragment 1', onSecondLink);
};
var onSecondLink = function() {
var links = casper.page.evaluate(function() {
return document.querySelectorAll("div#icinga-main a");
});
this.test.assertTitle("Icinga test page");
this.test.assertUrlMatch(/.*testFragment2.html/);
this.test.assertEquals(links.length, 2);
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment3.html?this=is_a_param", "icinga-detail");
});
});
this.wait(400, function() {
console.log(casper.page.evaluate(function() {
return window.location.href;
}));
this.test.assertUrlMatch(/testFragment2.html.*testFragment3.html/);
});
};
casper.run(function() {
this.test.done();
});

View File

@ -0,0 +1,175 @@
/**
* Test case for the login page
*
* Steps:
* - Request application root path
* - Assert login page to appear
* - Enter invalid credentials
* - Enter valid credentials
* - Reload page without credentials
* - Logout
**/
/**
* The icinga util object
*
* @type object
*/
var icinga = require('./icingawebtest');
/**
* The casperjs object
*
* @type Casper
*/
var casper = icinga.getTestEnv();
/**
* Test whether the login form exists and has valid input elements
*
* @param {testing} The casperjs testing module to perform assertions
*/
var assertLoginFormExists = function(test) {
test.assertExists(
'form#login',
'Test whether the login form exists'
);
test.assertExists(
'form#login input#username',
'Test whether a username input field exists'
);
test.assertExists(
'form#login input#password',
'Test whether a password input field exists'
);
test.assertExists(
'form#login input#submit',
'Test whether a submit input field exists'
);
};
/**
* Request the initial application path
*/
casper.start('/', function() {
if (this.getCurrentUrl() === 'about:blank') {
this.die('Url can\'t be accessed');
}
this.test.assertTitle(
"Icinga Web Login",
"Test whether the login page (" + this.getCurrentUrl() + ") has a correct title"
);
assertLoginFormExists(this.test);
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after initial page load'
);
});
/**
* Login with invalid credentials
*/
casper.then(function() {
this.fill('form#login', {
'username' : 'no',
'password' : 'existing_user'
});
this.click('form#login input#submit');
});
/**
* Test if login failed and feedback is given
*/
casper.then(function() {
this.test.assertTextExists(
'Please provide a valid username and password',
'Test if the user gets a note that authorization failed if providing wrong credentials'
);
assertLoginFormExists(this.test);
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after entering wrong credentials'
);
});
/**
* Login with valid credentials
*/
casper.then(function() {
this.fill('form#login', icinga.getCredentials());
this.click('form#login input#submit');
});
/**
* Test if the login suceeded and the username is shown in the navigation bar
*/
casper.then(function() {
this.test.assertTextDoesntExist(
'Please provide a valid username and password',
'Test if valid credentials don\'t end cause a note that credentials are wrong to appear'
);
this.test.assertSelectorHasText(
'#icinga_app_nav_username',
icinga.getCredentials().username,
'Test if the username is set in the frontend after successful login'
);
});
/**
* Test if session is persisted after reloading the page
*/
casper.thenOpen('/', function() {
this.test.assertSelectorHasText(
'#icinga_app_nav_username',
icinga.getCredentials().username,
'Test if the username is still set if reloading the page via GET'
);
this.test.assertExists(
'#icinga_app_nav_logout',
'Test if the logout button exists'
);
this.test.assertExists(
'#icinga_app_nav_useraction',
'Test whether the dropdown for user specific actions exists'
);
});
/**
* Test if logout button is displayed when username is clicked and test for correct logout
*/
casper.then(function() {
this.test.assertNotVisible(
'#icinga_app_nav_logout',
'Test if the logout button is hidden when not clicked'
);
this.wait(500, function() { // wait until everything is initialized, sometimes this takes a while
this.click('#icinga_app_nav_useraction');
this.waitUntilVisible('#icinga_app_nav_logout', function() {
this.click('#icinga_app_nav_logout a');
this.waitForSelector('form#login', function() {
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after logout'
);
assertLoginFormExists(this.test);
});
}, function() {
this.test.assertVisible(
'#icinga_app_nav_logout',
'Test if the logout button is visible when click on username occurs'
);
}, 500);
});
});
/**
* Run the tests
*/
casper.run(function() {
this.test.done();
});

View File

@ -1,21 +0,0 @@
/**
*
* This test simply checks the icinga build server and tests
* if the title is correct
**/
i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
casper.start("http://localhost:12999/empty.html");
casper.then(function() {
this.test.assertTitle("Just an empty page");
});
casper.run(function() {
this.test.done();
});

View File

@ -1,5 +0,0 @@
{
"host": "localhost",
"port": 80,
"path": "icinga2-web"
}

View File

@ -1,158 +0,0 @@
/**
* Tools for setting up the casperjs tests
* mainly setting host, port and path path
**/
// load config files
var fs = require('fs');
var env = require('system').env;
var args = require('system').args;
var utils = require('utils');
var configFile = fs.absolute('./casperjs.config');
var host = null;
var port = null;
var path = null;
var verbose = false;
if (typeof(env.CASPERJS_HOST) === "string")
host = env.CASPERJS_HOST;
if (typeof(env.CASPERJS_PORT) === "string")
port = parseInt(env.CASPERJS_PORT, 10);
if (typeof(env.CASPERJS_PATH) === "string")
path = env.CASPERJS_PATH;
for (var i=0;i<args.length;i++) {
switch(args[i]) {
case '--verbose':
verbose = true;
break;
case '--configFile':
configFile = args[++i];
break;
case '--host':
host = args[++i];
break;
case '--port':
port = parseInt(args[++i], 10);
break;
case '--path':
path = args[++i];
break;
}
}
if (fs.isReadable(configFile)) {
var cfg = fs.read(configFile);
try {
config = JSON.parse(cfg);
if(host === null)
host = config.host;
if(port === null)
port = parseInt(config.port, 10);
if(path === null)
path = config.path;
} catch(e) {
console.error("Configuration "+cfg+" is invalid: "+e);
}
}
if (host === null)
throw "Can't initialize tests: No host given in casperjs.config or via CASPERJS_HOST environment";
if (port === null)
throw "Can't initialize tests: No port given in casperjs.config or via CASPERJS_PORT environment";
if (path === null)
throw "Can't initialize tests: No path given in casperjs.config or via CASPERJS_PATH environment";
(function() {
"use strict";
var getBaseURL = function(url) {
url = url || "";
if (url.substr(0,4) == "http") {
return url;
}
url = "http://"+host+":"+port+"/"+path+"/"+url;
};
var cstart = casper.start;
var copen = casper.open;
var copenFrom = casper.openFrom;
var startFromBase = function(url, then) {
return cstart.apply(casper,[this.getBaseURL(url), then]);
};
var thenOpenFromBase = function(url, options) {
return copen.apply(casper,[this.getBaseURL(url), options]);
};
var openFromBase = function(url, options) {
return copenFrom.apply(casper,[this.getBaseURL(url), options]);
};
casper.on('remote.message', function(message) {
console.log(message);
});
casper.on('page.error', function(message, trace) {
console.error(message, JSON.stringify(trace));
});
exports.getTestEnv = function() {
casper.getBaseURL = getBaseURL;
casper.start = startFromBase;
casper.thenOpen = thenOpenFromBase;
casper.open = openFromBase;
return casper;
};
exports.setupRequireJs = function(libraries) {
if (typeof libraries === "undefined") {
libraries = {
jquery: 'vendor/jquery-1.8.3',
bootstrap: 'vendor/bootstrap.min',
eve: 'vendor/raphael/eve'
};
} else {
libraries = libraries || {};
libraries.logging = 'icinga/util/logging';
libraries.jquery = 'vendor/jquery-1.8.3';
libraries["modules/list"] = "/moduleMock";
if (libraries.bootstrap || libraries.icinga) {
libraries.bootstrap = 'vendor/bootstrap.min';
libraries.history = 'vendor/history';
libraries.eve = 'vendor/raphael/eve';
libraries.raphael = 'vendor/raphael/raphael.amd';
libraries["raphael.core"] = 'vendor/raphael/raphael.core';
libraries["raphael.svg"] = 'vendor/raphael/raphael.svg';
libraries["raphael.vml"] = 'vendor/raphael/raphael.vml';
}
if (libraries.ace) {
libraries.ace = 'vendor/ace/ace';
}
}
var bootstrap = libraries.icinga;
delete(libraries.icinga);
requirejs.config({
baseUrl: window.base_url + '/js',
paths: libraries
});
if (bootstrap) {
requirejs(['jquery', 'history']);
requirejs(['bootstrap']);
requirejs(['icinga/icinga'], function (Icinga) {
window.$ = $;
window.jQuery = $;
window.Icinga = Icinga;
window.History = History;
});
}
};
})();

View File

@ -0,0 +1,112 @@
/**
* Tools for setting up the casperjs tests
* mainly setting host, port and path path
**/
// load config files
var fs = require('fs');
var env = require('system').env;
var args = require('system').args;
var utils = require('utils');
var host = 'localhost';
var port = 80;
var path = 'icingaweb';
var verbose = false;
var user = 'jdoe';
var pass = 'password';
if (typeof(env.CASPERJS_HOST) === 'string')
host = env.CASPERJS_HOST;
if (typeof(env.CASPERJS_PORT) === 'string')
port = parseInt(env.CASPERJS_PORT, 10);
if (typeof(env.CASPERJS_PATH) === 'string')
path = env.CASPERJS_PATH;
if (typeof(env.CASPERJS_USER) === 'string')
user = env.CASPERJS_USER;
if (typeof(env.CASPERJS_PASS) === 'string')
pass = env.CASPERJS_PASS;
for (var i=0;i<args.length;i++) {
switch(args[i]) {
case '--verbose':
verbose = true;
break;
case '--host':
host = args[++i];
break;
case '--port':
port = parseInt(args[++i], 10);
break;
case '--path':
path = args[++i];
break;
}
}
if (host === null) {
console.error('Can\'t initialize tests: No host given in casperjs.config or via CASPERJS_HOST environment');
return false;
}
if (port === null) {
console.error('Can\'t initialize tests: No port given in casperjs.config or via CASPERJS_PORT environment');
return false;
}
if (path === null) {
console.error('Can\'t initialize tests: No path given in casperjs.config or via CASPERJS_PATH environment');
return false;
}
(function() {
'use strict';
var getBaseURL = function(url) {
url = url || '';
if (url.substr(0,4) == 'http') {
return url;
}
return 'http://'+host+':'+port+'/'+path+'/'+url;
};
var cstart = casper.start;
var cthenOpen = casper.thenOpen;
var copen = casper.open;
var startFromBase = function(url, then) {
return cstart.call(casper, this.getBaseURL(url), then);
};
var thenOpenFromBase = function(url, options) {
return cthenOpen.apply(casper, [this.getBaseURL(url), options]);
};
var openFromBase = function(url, options) {
return copen.apply(casper, [this.getBaseURL(url), options]);
};
casper.on('remote.message', function(message) {
console.log(message);
});
casper.on('page.error', function(message, trace) {
console.error(message, JSON.stringify(trace));
});
exports.getTestEnv = function() {
casper.getBaseURL = getBaseURL;
casper.start = startFromBase;
casper.thenOpen = thenOpenFromBase;
casper.open = openFromBase;
return casper;
};
exports.getCredentials = function() {
return {
'username' : user,
'password' : pass
};
};
})();

View File

@ -1,51 +0,0 @@
/**
*
* Regression test for #4408
# History api double encodes and causes messy behaviour
*
**/
var i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
var URL = "http://localhost:12999";
var firstLink = "/fragments/testFragment1.html?c[test]=test_test";
var secondLink = "/fragments/testFragment3.html?this=is_a_param";
casper.start(URL+"/generic.html");
casper.then(function() {
casper.page.evaluate(i2w.setupRequireJs, {icinga: true});
});
casper.then(function() {
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment1.html?c[test]=test_test");
});
});
casper.waitForSelector("div#icinga-main a", onFirstCall);
});
/**
* First call of the loadUrl
**/
var onFirstCall = function() {
this.test.assertUrlMatch(URL+firstLink);
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment3.html?this=is_a_param", "icinga-detail");
});
});
this.wait(400, function() {
var expected =
URL +
firstLink+"&c[icinga-detail]=" +
secondLink;
this.test.assertUrlMatch(expected);
});
};
casper.run(function() {
this.test.done();
});

View File

@ -1 +0,0 @@
test

View File

@ -11,15 +11,17 @@ VERBOSE=0
VAGRANT=0
BUILD=0
CASPERJS_HOST="localhost"
CASPERJS_PORT=80
CASPERJS_USER="jdoe"
CASPERJS_PASS="password"
CASPERJS_PATH="icingaweb"
if [ ! -x $CASPER ]; then
echo "CasperJS is not installed but required to run frontend tests\n"\
"Take a look at http://casperjs.org/installation.html to see how the installation works for your system"
exit 1
fi;
if [ ! -e "${DIR}/static/public" ]; then
echo "!"
ln -s "${DIR}/../../public" "${DIR}/static/public"
fi;
PARAM="0"
@ -48,16 +50,41 @@ for arg in $@;do
BUILD=1
continue
;;
-h|--host)
PARAM="CASPERJS_HOST"
continue
;;
-p|--port)
PARAM="CASPERJS_PORT"
continue
;;
--path)
PARAM="CASPERJS_PATH"
continue
;;
-U|--user)
PARAM="CASPERJS_USER"
continue
;;
-P|--pass)
PARAM="CASPERJS_PASS"
continue
;;
**)
if [ "$arg" != "--help" ]; then
echo "Unknown option $arg"
fi;
printf "%b" "Testrunner for interface tests\n\n"
printf "%b" "Usage: ./$0 [--verbose] [--include %include%] [--exclude %exclude%] [--build]\n\n"
printf "%b" "Usage: $0 [--verbose] [--include %include%] [--exclude %exclude%] [--build]\n\n"
printf "%b" " --verbose \t\t\t Print verbose output when testing\n"
printf "%b" " --include %filelist%\t\t Include only files matching this patterns\n"
printf "%b" " --exclude %filelist%\t\t Exclude files matching this patterns\n"
printf "%b" " --build \t\t\t Write test results to ../../build/log/casper_results.xml\n"
printf "%b" " --host \t\t\t Host to run frontend tests on, default is localhost\n"
printf "%b" " --port \t\t\t Port to use for the host, default is 80 \n"
printf "%b" " --path \t\t\t Base path where icinga can be found (default is icingaweb)\n"
printf "%b" " --user \t\t\t User to use for authentication (default jdoe)\n"
printf "%b" " --pass \t\t\t Password to use for authentication (default password)\n"
printf "%b" " --help \t\t\t Print this message\n\n"
exit 1
esac;
@ -84,7 +111,7 @@ if [ "$CASPER" = "" -o ! -x $CASPER ]; then
exit 1
fi;
EXEC="$CASPER test"
EXEC="$CASPER test --ignore-ssl-errors=true "
#
# If build is set, the results are written for our jenkins server
@ -137,16 +164,13 @@ if [ "$EXCLUDE" != "" ];then
FILELIST=`echo $FILELIST | grep -v "$NAME"`
fi;
cd $DIR/static
PROC=`ps ax|grep "SimpleHTTPServer 12999"|awk '{ print $1 }'`
if [ "$PROC" != "" ]; then
kill $PROC
fi;
python -m SimpleHTTPServer 12999&
PID=$!
cd $DIR
echo $EXEC $FILELIST
export CASPERJS_HOST=$CASPERJS_HOST
export CASPERJS_PORT=$CASPERJS_PORT
export CASPERJS_USER=$CASPERJS_USER
export CASPERJS_PASS=$CASPERJS_PASS
export CASPERJS_PATH=$CASPERJS_PATH
echo Executing $EXEC $FILELIST
$EXEC $FILELIST
kill $PID
exit 0

View File

@ -1,7 +0,0 @@
<html>
<head>
<title>Just an empty page</title>
</head>
<body>
</body>
</html>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment</h1>
<a href="/fragments/testFragment2.html?this=istesting">Fragment 2</a>
<a href="/fragments/testFragment3.html">Fragment 3</a>
</div>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment 2</h1>
<a href="/fragments/testFragment1.html">Fragment 1</a>
<a href="/fragments/testFragment3.html">Fragment 3</a>
</div>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment 3</h1>
<a href="/fragments/testfragment1.html">Fragment 1</a>
<a href="/fragments/testfragment2.html">Fragment 2</a>
</div>

View File

@ -1,39 +0,0 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Icinga test page</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script>
window.base_url = "/public";
</script>
<link rel="stylesheet" href="/public/css/normalize.min.css">
<link rel="stylesheet" href="/public/css/vendor/bootstrap.css">
<link rel="stylesheet" href="/public/css/main.css">
<link rel="stylesheet" href="/public/css/vendor/jquery.qtip.min.css">
<script src="/public/js/vendor/modernizr-2.6.2.min.js"></script>
<link rel="stylesheet" href="/public/css/icinga.css">
<link rel="stylesheet" href="/public/css/vendor/bootstrap-responsive.min.css">
<script src="/public/js/vendor/require.js"></script>
</head>
<body class="cranberry">
<div class="main">
<div class="tabbable tabs-left" style="height:100%;">
</div>
<div class="layout-main-detail collapsed">
<div id="icinga-main" container-id="icinga-main" class="icinga-container">
</div>
<div id="icinga-detail" class="icinga-container " container-id="icinga-detail">
</div><!-- End of icinga-detail -->
</div><!-- End of layout-main-detail -->
</div><!-- End of main -->
</body>
</html>

View File

@ -1,4 +0,0 @@
define([], function() {
"use strict";
return {};
});

View File

@ -1 +0,0 @@
<testsuite time="0"><testcase classname="cases/static-page-test" name="The jenkins page" time="0.626"><failure type="assertTitle">Page title is: "i4cinga-web test [Jenkins]"</failure></testcase></testsuite>