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.
190 lines
6.8 KiB
190 lines
6.8 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> |
|
|
|
#include <version.hxx> |
|
using namespace NAMESPACE; |
|
|
|
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 format(std::string txt, int indent = 2, int cpl = 60) { |
|
return format(QString::fromStdString(txt), indent, cpl); |
|
} |
|
|
|
QString help(const Script& s) { |
|
std::ostringstream ss; |
|
ss<<"Synopsis"<<std::endl |
|
<<std::endl |
|
<<" webrunner [<OPTIONS>] [<file1> [<file2> [...]]]"<<std::endl |
|
<<std::endl |
|
<<"DESCRIPTION"<<std::endl |
|
<<std::endl |
|
<<format(description()).toStdString()<<std::endl |
|
<<std::endl |
|
<<format(readme()).toStdString()<<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<<std::endl |
|
<<" from package "<<package_string()<<std::endl |
|
<<" by "<<author()<<std::endl |
|
<<" built on "<<build_date()<<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; |
|
}
|
|
|