Test your websites with this simple GUI based scripted webtester. Generate simple testscripts directly from surfng on the webpage, enhance them with your commands, with variables, loops, checks, … and finally run automated web tests.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
6.3 KiB
178 lines
6.3 KiB
9 years ago
|
#include <commands.hxx>
|
||
|
#include <webpage.hxx>
|
||
|
#include <QApplication>
|
||
|
#include <QFile>
|
||
|
#include <QWebView>
|
||
|
#include <QStringList>
|
||
|
#include <QCommandLineParser>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <fstream>
|
||
|
#include <QDateTime>
|
||
|
|
||
|
#include <xml-cxx/xml.hxx>
|
||
|
#include <mrw/string.hxx>
|
||
|
|
||
|
std::string VERSION("0.9.4");
|
||
|
|
||
|
QString format(QString txt, int indent = 2, int cpl = 60) {
|
||
|
QStringList res;
|
||
|
QStringList lines(txt.split('\n'));
|
||
|
QString ind(indent, ' ');
|
||
|
Q_FOREACH(QString line, lines) {
|
||
|
line.insert(0, ind);
|
||
|
for (int pos(0); line.size()-pos>cpl; ++pos) {
|
||
|
pos=line.lastIndexOf(' ', pos+cpl);
|
||
|
line.remove(pos, 1);
|
||
|
line.insert(pos, "\n"+ind);
|
||
|
}
|
||
|
res+=line;
|
||
|
}
|
||
|
return res.join('\n');
|
||
|
}
|
||
|
|
||
|
QString help(const Script& s) {
|
||
|
std::ostringstream ss;
|
||
|
ss<<"Synopsis"<<std::endl
|
||
|
<<std::endl
|
||
|
<<" webrunner [<OPTIONS>] [<file1> [<file2> [...]]]"<<std::endl
|
||
|
<<std::endl
|
||
|
<<"Script Syntax"<<std::endl
|
||
|
<<std::endl
|
||
|
<<format(s.syntax()).toStdString()<<std::endl
|
||
|
<<std::endl
|
||
|
<<"Script Commands"<<std::endl
|
||
|
<<std::endl
|
||
|
<<format(s.commands()).toStdString()<<std::endl;
|
||
|
return QString::fromStdString(ss.str());
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) try {
|
||
|
bool failed(false);
|
||
|
QApplication a(argc, argv);
|
||
|
QWebView p;
|
||
|
p.setPage(new TestWebPage(&p, true));
|
||
|
QCommandLineParser parser;
|
||
|
Script script;
|
||
|
parser.setApplicationDescription(help(script));
|
||
|
parser.addHelpOption();
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"x"<<"xml",
|
||
|
"store XML output in <xmlfile>", "xmlfile"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"r"<<"retries",
|
||
|
"on error retry up to <maxretries> times",
|
||
|
"maxretries", "0"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"W"<<"width",
|
||
|
"set screenshot size to <width> pixel", "width", "2048"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"H"<<"height",
|
||
|
"set screenshot size to <height> pixel", "height", "2048"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"v"<<"version",
|
||
|
"show version information"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"s"<<"skipped",
|
||
|
"treat skipped test cases as failure in XML output file"));
|
||
|
parser.addOption(QCommandLineOption
|
||
|
(QStringList()<<"t"<<"target-path",
|
||
|
"set screenshot target path to <path>", "path",
|
||
|
QDir().absolutePath()+QDir::separator()+"attachments"));
|
||
|
parser.process(a);
|
||
|
if (parser.isSet("version")) {
|
||
|
std::cout<<*argv<<" "<<VERSION<<std::endl;
|
||
|
return 0;
|
||
|
}
|
||
|
int retries(parser.value("retries").toInt());
|
||
|
int width(parser.value("width").toInt());
|
||
|
int height(parser.value("height").toInt());
|
||
|
QString target(parser.value("target-path"));
|
||
|
p.resize(width, height);
|
||
|
xml::Node testsuites("testsuites");
|
||
|
Q_FOREACH(QString file, parser.positionalArguments()) {
|
||
|
int expectedtestcases(-1);
|
||
|
xml::Node testsuite("testsuite");
|
||
|
testsuite.attr("name") = QFileInfo(file).baseName().toStdString();
|
||
|
testsuite.attr("timestamp") =
|
||
|
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();
|
||
|
xml::Node testcase("testcase");
|
||
|
testcase.attr("classname") = "testsuite-preparation";
|
||
|
try {
|
||
|
script.reset();
|
||
|
script.log("=====================");
|
||
|
script.log("TEST: "+file);
|
||
|
script.log("---------------------");
|
||
|
testcase.attr("name") = "open test suite file";
|
||
|
testsuite<<testcase;
|
||
|
QFile f(file);
|
||
|
if (!f.open(QIODevice::ReadOnly))
|
||
|
throw std::runtime_error("cannot open file "+file.toStdString());
|
||
|
QString txt(QString::fromUtf8(f.readAll()));
|
||
|
testcase.attr("name") = "parse test suite file";
|
||
|
testsuite<<testcase;
|
||
|
script.parse(txt.split('\n'));
|
||
|
expectedtestcases = script.steps()+2;
|
||
|
if (failed) {
|
||
|
script.log("FAILED: "+file+" skipped due to previous error");
|
||
|
testcase.attr("name") = "testsuite";
|
||
|
xml::Node failure("failure");
|
||
|
failure.attr("message") = "ignored due to previous failure";
|
||
|
testsuite<<(testcase<<failure);
|
||
|
testsuite.attr("failures") =
|
||
|
mrw::string(expectedtestcases+1-testsuite.children());
|
||
|
if (parser.isSet("skipped")) {
|
||
|
testcase.attr("name") = "skipped test case";
|
||
|
failure.attr("message") = "skipped due to previous failure";
|
||
|
testcase<<failure;
|
||
|
for (int i(testsuite.children()); i<expectedtestcases; ++i)
|
||
|
testsuite<<testcase;
|
||
|
}
|
||
|
} else {
|
||
|
script.run(p.page()->mainFrame(), testsuite,
|
||
|
target+QDir::separator()+QFileInfo(file).baseName(),
|
||
|
true, retries);
|
||
|
testsuite.attr("failures") = "0";
|
||
|
script.log("SUCCESS: "+file);
|
||
|
}
|
||
|
} catch (std::exception& e) {
|
||
|
script.log("FAILED: "+file+" with "+e.what());
|
||
|
xml::Node failure("failure");
|
||
|
failure.attr("message") = Script::xmlattr(e.what()).toStdString();
|
||
|
testsuite[testsuite.children()-1]<<failure;
|
||
|
if (expectedtestcases==-1)
|
||
|
testsuite.attr("failures") = "1";
|
||
|
else
|
||
|
testsuite.attr("failures") =
|
||
|
mrw::string(expectedtestcases+1-testsuite.children());
|
||
|
if (parser.isSet("skipped")) {
|
||
|
testcase.attr("name") = "skipped test case";
|
||
|
failure.attr("message") = "skipped due to previous failure";
|
||
|
testcase<<failure;
|
||
|
for (int i(testsuite.children()); i<expectedtestcases; ++i)
|
||
|
testsuite<<testcase;
|
||
|
failed = true;
|
||
|
}
|
||
|
}
|
||
|
if (expectedtestcases==-1) {
|
||
|
testsuite.attr("tests") = mrw::string(testsuite.children());
|
||
|
} else {
|
||
|
testsuite.attr("tests") = mrw::string(expectedtestcases);
|
||
|
}
|
||
|
if (script.cout().size())
|
||
|
testsuite<<(xml::String("system-out") =
|
||
|
script.xmlattr(script.cout()).toStdString());
|
||
|
if (script.cerr().size())
|
||
|
testsuite<<(xml::String("system-err") =
|
||
|
script.xmlattr(script.cerr()).toStdString());
|
||
|
testsuites<<testsuite;
|
||
|
}
|
||
|
if (parser.isSet("xml")) { // todo: write xml file
|
||
|
std::ofstream xmlfile(parser.value("xml").toStdString());
|
||
|
xmlfile<<testsuites<<std::endl;
|
||
|
}
|
||
|
return failed ? 1 : 0;
|
||
|
} catch (std::exception& e) {
|
||
|
return 1;
|
||
|
}
|