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.
 
 
 
 
 
 

177 lines
6.3 KiB

#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.5");
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;
}