more improve expect load; better logging in case of exception

master
Marc Wäckerlin 7 years ago
parent 006a5a2e6e
commit 35f5aa9676
  1. 237
      src/commands.hxx

@ -98,6 +98,10 @@ class Command: public QObject {
virtual std::shared_ptr<Command> parse(Script*, QString, virtual std::shared_ptr<Command> parse(Script*, QString,
QStringList&, QString, int, int) = 0; QStringList&, QString, int, int) = 0;
virtual bool execute(Script*, QWebFrame*) = 0; virtual bool execute(Script*, QWebFrame*) = 0;
static void error(Logger& log, const Exception& e) {
log(QString(" FAILED: ")+e.what());
throw e;
}
void line(int linenr) { void line(int linenr) {
_line = linenr; _line = linenr;
} }
@ -128,9 +132,9 @@ class Command: public QObject {
virtual bool isTestcase() { virtual bool isTestcase() {
return true; return true;
} }
static void realMouseClick(QWebFrame* frame, QString selector) { static void realMouseClick(Logger& log, QWebFrame* frame, QString selector) {
QWebElement element(find(frame, selector)); QWebElement element(find(frame, selector));
if (element.isNull()) throw ElementNotFound(selector); if (element.isNull()) error(log, ElementNotFound(selector));
realMouseClick(element); realMouseClick(element);
} }
static void realMouseClick(const QWebElement& element) { static void realMouseClick(const QWebElement& element) {
@ -168,7 +172,7 @@ class Command: public QObject {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100); QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
} }
protected: protected:
bool runScript(Command* parentCommand, bool runScript(Logger& log, Command* parentCommand,
std::shared_ptr<Script> script, std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
QStringList vars = QStringList(), QStringList vars = QStringList(),
@ -299,10 +303,10 @@ class Comment: public Command {
class Screenshot: public Command { class Screenshot: public Command {
public: public:
static QString sourceHtml(int line, QString target, QString base, static QString sourceHtml(Logger& log, int line, QString target, QString base,
QString name, QWebFrame* frame) { QString name, QWebFrame* frame) {
if (!QDir(target).exists() && !QDir().mkpath(target)) if (!QDir(target).exists() && !QDir().mkpath(target))
throw DirectoryCannotBeCreated(target); error(log, DirectoryCannotBeCreated(target));
QCoreApplication::processEvents(); QCoreApplication::processEvents();
QString filename(target+QDir::separator()+ QString filename(target+QDir::separator()+
QString("%4-%1-%2-%3.html") QString("%4-%1-%2-%3.html")
@ -313,13 +317,13 @@ class Screenshot: public Command {
.toString("yyyyMMddHHmmss"))); .toString("yyyyMMddHHmmss")));
QFile file(filename); QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
throw CannotWriteSouceHTML(filename); error(log, CannotWriteSouceHTML(filename));
QTextStream out(&file); QTextStream out(&file);
out<<frame->toHtml(); out<<frame->toHtml();
if (out.status()!=QTextStream::Ok) throw CannotWriteSouceHTML(filename); if (out.status()!=QTextStream::Ok) error(log, CannotWriteSouceHTML(filename));
return QDir(filename).absolutePath(); return QDir(filename).absolutePath();
} }
static QString screenshot(int line, QString target, QString base, static QString screenshot(Logger& log, int line, QString target, QString base,
QString name, QWebFrame* frame) { QString name, QWebFrame* frame) {
bool wasShown(frame->page()->view()->isVisible()); bool wasShown(frame->page()->view()->isVisible());
frame->page()->view()->show(); frame->page()->view()->show();
@ -330,7 +334,7 @@ class Screenshot: public Command {
painter.end(); painter.end();
if (!wasShown) frame->page()->view()->hide(); if (!wasShown) frame->page()->view()->hide();
if (!QDir(target).exists() && !QDir().mkpath(target)) if (!QDir(target).exists() && !QDir().mkpath(target))
throw DirectoryCannotBeCreated(target); error(log, DirectoryCannotBeCreated(target));
QCoreApplication::processEvents(); QCoreApplication::processEvents();
QString filename(target+QDir::separator()+ QString filename(target+QDir::separator()+
QString("%4-%1-%2-%3.png") QString("%4-%1-%2-%3.png")
@ -339,7 +343,7 @@ class Screenshot: public Command {
.arg(name) .arg(name)
.arg(QDateTime::currentDateTime() .arg(QDateTime::currentDateTime()
.toString("yyyyMMddHHmmss"))); .toString("yyyyMMddHHmmss")));
if (!image.save(filename)) throw CannotWriteScreenshot(filename); if (!image.save(filename)) error(log, CannotWriteScreenshot(filename));
return QDir(filename).absolutePath(); return QDir(filename).absolutePath();
} }
QString tag() const { QString tag() const {
@ -639,8 +643,9 @@ class Script: public QObject {
// timeout may happen during load due to bad internet connection // timeout may happen during load due to bad internet connection
if (screenshots) if (screenshots)
try { // take a screenshot on error try { // take a screenshot on error
Logger log(0, this);
QString filename(Screenshot::screenshot QString filename(Screenshot::screenshot
((*cmd)->line(), targetdir(), (log, (*cmd)->line(), targetdir(),
_testclass, _testclass,
QString("retry-%1") QString("retry-%1")
.arg((ulong)retries, 2, 10, .arg((ulong)retries, 2, 10,
@ -717,14 +722,16 @@ class Script: public QObject {
if (screenshots) if (screenshots)
try { // write html source and take a last screenshot on error try { // write html source and take a last screenshot on error
{ {
Logger log(0, this);
QString filename(Screenshot::sourceHtml QString filename(Screenshot::sourceHtml
((*cmd)->line(), targetdir(), (log, (*cmd)->line(), targetdir(),
_testclass, _testclass,
"error", frame)); "error", frame));
plainlog("[[ATTACHMENT|"+filename+"]]"); plainlog("[[ATTACHMENT|"+filename+"]]");
} { } {
Logger log(0, this);
QString filename(Screenshot::screenshot QString filename(Screenshot::screenshot
((*cmd)->line(), targetdir(), (log, (*cmd)->line(), targetdir(),
_testclass, _testclass,
"error", frame)); "error", frame));
plainlog("[[ATTACHMENT|"+filename+"]]"); plainlog("[[ATTACHMENT|"+filename+"]]");
@ -734,7 +741,7 @@ class Script: public QObject {
} }
} }
removeSignals(frame); removeSignals(frame);
if (!_signals.empty()) throw UnhandledSignals(_signals); if (!_signals.empty()) error(UnhandledSignals(_signals));
progress("success", 0, 0); progress("success", 0, 0);
return res; return res;
} }
@ -798,9 +805,9 @@ class Script: public QObject {
QStringList variables() { QStringList variables() {
return _variables.keys(); return _variables.keys();
} }
QString variable(QString name) { QString variable(Logger& log, QString name) {
QMap<QString, QString>::iterator it(_variables.find(name)); QMap<QString, QString>::iterator it(_variables.find(name));
if (it==_variables.end()) throw VariableNotFound(name); if (it==_variables.end()) error(VariableNotFound(name));
return *it; return *it;
} }
/// Copy context from other script /// Copy context from other script
@ -829,10 +836,10 @@ class Script: public QObject {
void function(QString name, std::shared_ptr<Function> f) { void function(QString name, std::shared_ptr<Function> f) {
_functions[name] = f; _functions[name] = f;
} }
std::shared_ptr<Function> function(QString name) { std::shared_ptr<Function> function(Logger& log, QString name) {
QMap<QString, std::shared_ptr<Function> >::iterator QMap<QString, std::shared_ptr<Function> >::iterator
it(_functions.find(name)); it(_functions.find(name));
if (it==_functions.end()) throw FunctionNotFound(name); if (it==_functions.end()) error(FunctionNotFound(name));
return *it; return *it;
} }
void timeout(int t) { void timeout(int t) {
@ -942,6 +949,10 @@ class Script: public QObject {
_cout += text + "\n"; _cout += text + "\n";
} }
private: private:
void error(const Exception& e) {
log(QString(" FAILED: ")+e.what());
throw e;
}
std::shared_ptr<Command> unknown(QString command) { std::shared_ptr<Command> unknown(QString command) {
if (!command.size()) if (!command.size())
return std::shared_ptr<Command>(new Empty()); return std::shared_ptr<Command>(new Empty());
@ -998,7 +1009,7 @@ class Script: public QObject {
QStringList(url.toString()))); QStringList(url.toString())));
} }
void timeout() { void timeout() {
throw TimeOut(); error(TimeOut());
} }
private: private:
typedef std::map<QString, std::shared_ptr<Command>> Prototypes; typedef std::map<QString, std::shared_ptr<Command>> Prototypes;
@ -1056,7 +1067,7 @@ class Do: public Command {
if (_selector.size()) { if (_selector.size()) {
element = find(frame, script->replacevars(_selector)); element = find(frame, script->replacevars(_selector));
if (element.isNull()) if (element.isNull())
throw ElementNotFound(script->replacevars(_selector)); error(log, ElementNotFound(script->replacevars(_selector)));
} }
_result = _result =
element.evaluateJavaScript(script->replacevars(_javascript)).toString(); element.evaluateJavaScript(script->replacevars(_javascript)).toString();
@ -1138,19 +1149,19 @@ class Expect: public Command {
QStringList args(script->replacevars(_signal._args)); QStringList args(script->replacevars(_signal._args));
Script::Signal lastsignal(script->getSignal()); Script::Signal lastsignal(script->getSignal());
if (_signal._signal=="load") { // special signal load if (_signal._signal=="load") { // special signal load
if (lastsignal.first=="loadStarted") { while (lastsignal.first=="loadStarted") {
log("ignore loadStarted"); log("ignore signal: loadStarted");
lastsignal = script->getSignal(); // ignore optional loadStarted lastsignal = script->getSignal(); // ignore optional loadStarted
} }
if (lastsignal.first!="urlChanged" || (args.size() && lastsignal.second!=args)) if (lastsignal.first!="urlChanged" || (args.size() && lastsignal.second!=args))
throw WrongSignal("urlChanged", args, lastsignal); error(log, WrongSignal("urlChanged", args, lastsignal));
lastsignal = script->getSignal(); lastsignal = script->getSignal();
args=QStringList("true"); args=QStringList("true");
if (lastsignal.first!="loadFinished" || (lastsignal.second!=args)) if (lastsignal.first!="loadFinished" || (lastsignal.second!=args))
throw WrongSignal("loadFinished", args, lastsignal); error(log, WrongSignal("loadFinished", args, lastsignal));
} else { } else {
if (lastsignal.first!=_signal._signal || (args.size() && lastsignal.second!=args)) if (lastsignal.first!=_signal._signal || (args.size() && lastsignal.second!=args))
throw WrongSignal(_signal._signal, args, lastsignal); error(log, WrongSignal(_signal._signal, args, lastsignal));
} }
return true; return true;
} }
@ -1221,8 +1232,8 @@ class Sleep: public Command {
bool ok; bool ok;
unsigned int time(script->replacevars(_time).toUInt(&ok)); unsigned int time(script->replacevars(_time).toUInt(&ok));
if (!ok) if (!ok)
throw BadArgument(script->replacevars(_time) error(log, BadArgument(script->replacevars(_time)
+" should be a number of seconds"); +" should be a number of seconds"));
sleep(time); sleep(time);
return true; return true;
} }
@ -1342,7 +1353,7 @@ class Upload: public Command {
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) if (allargs.size()<2)
throw BadArgument(tag()+"requires <selector> -> <filename>, " throw BadArgument(tag()+"requires <selector> -> <filename>, "
"instead of: \""+args+"\""); "instead of: \""+args+"\"");
cmd->_selector = allargs.takeFirst().trimmed(); cmd->_selector = allargs.takeFirst().trimmed();
cmd->_filename = allargs.join("->").trimmed(); cmd->_filename = allargs.join("->").trimmed();
return cmd; return cmd;
@ -1364,9 +1375,9 @@ class Upload: public Command {
if (files.size()==1) filename=files[0]; if (files.size()==1) filename=files[0];
} }
page->setNextUploadFile(filename); page->setNextUploadFile(filename);
realMouseClick(frame, script->replacevars(_selector)); realMouseClick(log, frame, script->replacevars(_selector));
if (page->uploadPrepared()) if (page->uploadPrepared())
throw SetFileUploadFailed(script->replacevars(_selector), filename); error(log, SetFileUploadFailed(script->replacevars(_selector), filename));
return true; return true;
} }
private: private:
@ -1416,14 +1427,14 @@ class Exists: public Command {
} }
QWebElement element(find(frame, selector)); QWebElement element(find(frame, selector));
if (text.isEmpty()) if (text.isEmpty())
throw AssertionFailed("element not found: "+selector); error(log, AssertionFailed("element not found: "+selector));
else if (element.isNull()) else if (element.isNull())
throw AssertionFailed("expected \""+text+"\" in non existing element " error(log, AssertionFailed("expected \""+text+"\" in non existing element "
+selector); +selector));
else else
throw AssertionFailed("not found \""+text+"\" in \"" error(log, AssertionFailed("not found \""+text+"\" in \""
+notfound.join("\", \"")+"\" on "+selector); +notfound.join("\", \"")+"\" on "+selector));
return true; // never reached due to throw above return true; // never reached due to error, above
} }
private: private:
QString _selector; QString _selector;
@ -1465,10 +1476,10 @@ class Not: public Command {
QString text(script->replacevars(_text)); QString text(script->replacevars(_text));
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) { Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
if (text.isEmpty()) if (text.isEmpty())
throw AssertionFailed("element must not exists: "+selector); error(log, AssertionFailed("element must not exists: "+selector));
if (element.toOuterXml().indexOf(text)!=-1) if (element.toOuterXml().indexOf(text)!=-1)
throw AssertionFailed("\""+text+"\" must not be in \"" error(log, AssertionFailed("\""+text+"\" must not be in \""
+element.toInnerXml()+"\" on "+selector); +element.toInnerXml()+"\" on "+selector));
} }
return true; return true;
} }
@ -1517,23 +1528,23 @@ class Execute: public Command {
exec.setProcessChannelMode(QProcess::MergedChannels); exec.setProcessChannelMode(QProcess::MergedChannels);
exec.start(command, args); exec.start(command, args);
if (!exec.waitForStarted()) if (!exec.waitForStarted())
throw CannotStartScript(command, args, scripttxt); error(log, CannotStartScript(command, args, scripttxt));
if (scripttxt.size()) { if (scripttxt.size()) {
if (exec.write(scripttxt.toUtf8())!=scripttxt.toUtf8().size() || if (exec.write(scripttxt.toUtf8())!=scripttxt.toUtf8().size() ||
!exec.waitForBytesWritten(60000)) !exec.waitForBytesWritten(60000))
throw CannotLoadScript(command, args, scripttxt); error(log, CannotLoadScript(command, args, scripttxt));
} }
exec.closeWriteChannel(); exec.closeWriteChannel();
if (!exec.waitForFinished(60000) && exec.state()!=QProcess::NotRunning) if (!exec.waitForFinished(60000) && exec.state()!=QProcess::NotRunning)
throw ScriptNotFinished(command, args, scripttxt); error(log, ScriptNotFinished(command, args, scripttxt));
QString stdout(exec.readAllStandardOutput()); QString stdout(exec.readAllStandardOutput());
QString stderr(exec.readAllStandardError()); QString stderr(exec.readAllStandardError());
_result = stdout; _result = stdout;
log("result: "+(_result.size()?_result:"(void)")); log("result: "+(_result.size()?_result:"(void)"));
script->log(stdout); script->log(stdout);
if (exec.exitCode()!=0 || exec.exitStatus()!=QProcess::NormalExit) if (exec.exitCode()!=0 || exec.exitStatus()!=QProcess::NormalExit)
throw ScriptExecutionFailed(command, args, scripttxt, error(log, ScriptExecutionFailed(command, args, scripttxt,
exec.exitCode(), stdout, stderr); exec.exitCode(), stdout, stderr));
return true; return true;
} }
private: private:
@ -1585,8 +1596,8 @@ class Download: public Command {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100); QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
log("download terminated "+ log("download terminated "+
QString(_netsuccess&&_filesuccess?"successfully":"with error")); QString(_netsuccess&&_filesuccess?"successfully":"with error"));
if (!_netsuccess) throw DownloadFailed(_realfilename); if (!_netsuccess) error(log, DownloadFailed(_realfilename));
if (!_filesuccess) throw WriteFileFailed(_realfilename); if (!_filesuccess) error(log, WriteFileFailed(_realfilename));
log["[[ATTACHMENT|"+QDir(_realfilename).absolutePath()+"]]"]; log["[[ATTACHMENT|"+QDir(_realfilename).absolutePath()+"]]"];
disconnect(frame->page(), SIGNAL(unsupportedContent(QNetworkReply*)), disconnect(frame->page(), SIGNAL(unsupportedContent(QNetworkReply*)),
this, SLOT(unsupportedContent(QNetworkReply*))); this, SLOT(unsupportedContent(QNetworkReply*)));
@ -1660,14 +1671,14 @@ class Click: public Command {
QString clicktarget(script->replacevars(_selector)); QString clicktarget(script->replacevars(_selector));
switch (_clicktype ? *_clicktype : script->clicktype()) { switch (_clicktype ? *_clicktype : script->clicktype()) {
case Script::REAL_MOUSE_CLICK: { case Script::REAL_MOUSE_CLICK: {
realMouseClick(frame, clicktarget); realMouseClick(log, frame, clicktarget);
break; break;
} }
case Script::JAVASCRIPT_CLICK: case Script::JAVASCRIPT_CLICK:
default: { default: {
QWebElement element(find(frame, clicktarget)); QWebElement element(find(frame, clicktarget));
if (element.isNull()) if (element.isNull())
throw ElementNotFound(clicktarget); error(log, ElementNotFound(clicktarget));
_result = element.evaluateJavaScript("this.click();").toString(); _result = element.evaluateJavaScript("this.click();").toString();
if (_result.size()) log("result: "+_result.size()); if (_result.size()) log("result: "+_result.size());
break; break;
@ -1791,8 +1802,8 @@ class Timeout: public Command {
Logger log(this, script); Logger log(this, script);
bool ok; bool ok;
int timeout(script->replacevars(_timeout).toInt(&ok)); int timeout(script->replacevars(_timeout).toInt(&ok));
if (!ok) throw BadArgument(script->replacevars(_timeout) if (!ok) error(log, BadArgument(script->replacevars(_timeout)
+" should be a number of seconds"); +" should be a number of seconds"));
script->timeout(timeout); script->timeout(timeout);
return true; return true;
} }
@ -1826,9 +1837,9 @@ class CaCertificate: public Command {
QFile cacertfile(script->path()+filename); QFile cacertfile(script->path()+filename);
if (!cacertfile.exists()) cacertfile.setFileName(filename); // try without path if (!cacertfile.exists()) cacertfile.setFileName(filename); // try without path
if (!cacertfile.exists() || !cacertfile.open(QIODevice::ReadOnly)) if (!cacertfile.exists() || !cacertfile.open(QIODevice::ReadOnly))
throw FileNotFound(filename); error(log, FileNotFound(filename));
QSslCertificate cacert(&cacertfile); QSslCertificate cacert(&cacertfile);
if (cacert.isNull()) throw NotACertificate(filename); if (cacert.isNull()) error(log, NotACertificate(filename));
QSslSocket::addDefaultCaCertificate(cacert); QSslSocket::addDefaultCaCertificate(cacert);
return true; return true;
} }
@ -1873,19 +1884,19 @@ class ClientCertificate: public Command {
QFile certfile(script->path()+filename); QFile certfile(script->path()+filename);
if (!certfile.exists()) certfile.setFileName(filename); if (!certfile.exists()) certfile.setFileName(filename);
if (!certfile.exists() || !certfile.open(QIODevice::ReadOnly)) if (!certfile.exists() || !certfile.open(QIODevice::ReadOnly))
throw FileNotFound(filename); error(log, FileNotFound(filename));
QSslCertificate cert(&certfile); QSslCertificate cert(&certfile);
if (cert.isNull()) throw NotACertificate(filename); if (cert.isNull()) error(log, NotACertificate(filename));
sslConfig.setLocalCertificate(cert); sslConfig.setLocalCertificate(cert);
filename = script->replacevars(_keyfile); filename = script->replacevars(_keyfile);
QFile keyfile(script->path()+filename); QFile keyfile(script->path()+filename);
if (!keyfile.exists()) keyfile.setFileName(filename); if (!keyfile.exists()) keyfile.setFileName(filename);
if (!keyfile.exists() || !keyfile.open(QIODevice::ReadOnly)) if (!keyfile.exists() || !keyfile.open(QIODevice::ReadOnly))
throw FileNotFound(filename); error(log, FileNotFound(filename));
keyfile.open(QIODevice::ReadOnly); keyfile.open(QIODevice::ReadOnly);
QSslKey k(&keyfile, QSsl::Rsa, QSsl::Pem, QSslKey k(&keyfile, QSsl::Rsa, QSsl::Pem,
QSsl::PrivateKey, script->replacevars(_password).toUtf8()); QSsl::PrivateKey, script->replacevars(_password).toUtf8());
if (k.isNull()) throw KeyNotReadable(filename); if (k.isNull()) error(log, KeyNotReadable(filename));
sslConfig.setPrivateKey(k); sslConfig.setPrivateKey(k);
QSslConfiguration::setDefaultConfiguration(sslConfig); QSslConfiguration::setDefaultConfiguration(sslConfig);
return true; return true;
@ -1970,7 +1981,7 @@ class SetValue: public Command {
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) if (allargs.size()<2)
throw BadArgument(tag()+" requires <selector> -> <value>, " throw BadArgument(tag()+" requires <selector> -> <value>, "
"instead of: \""+args+"\""); "instead of: \""+args+"\"");
cmd->_selector = allargs.takeFirst().trimmed(); cmd->_selector = allargs.takeFirst().trimmed();
cmd->_value = allargs.join("->").trimmed(); cmd->_value = allargs.join("->").trimmed();
return cmd; return cmd;
@ -1979,7 +1990,7 @@ class SetValue: public Command {
Logger log(this, script); Logger log(this, script);
QWebElement element(find(frame, script->replacevars(_selector))); QWebElement element(find(frame, script->replacevars(_selector)));
if (element.isNull()) if (element.isNull())
throw ElementNotFound(script->replacevars(_selector)); error(log, ElementNotFound(script->replacevars(_selector)));
QString value(script->replacevars(_value)); QString value(script->replacevars(_value));
if (element.tagName()=="SELECT") { if (element.tagName()=="SELECT") {
// value is a comma seperated list of option values // value is a comma seperated list of option values
@ -2045,12 +2056,12 @@ class Function: public Command {
Logger log(this, script, false); Logger log(this, script, false);
return true; return true;
} }
bool call(Command* parentCommand, QStringList args, bool call(Logger& log, Command* parentCommand, QStringList args,
Script* script, QWebFrame* frame) { Script* script, QWebFrame* frame) {
try { try {
return runScript(parentCommand, _script, script, frame, _vars, args); return runScript(log, parentCommand, _script, script, frame, _vars, args);
} catch (const std::exception& x) { } catch (const Exception& x) {
throw FunctionCallFailed(_name, _vars, args, x); error(log, FunctionCallFailed(_name, _vars, args, x));
} }
} }
private: private:
@ -2087,8 +2098,8 @@ class Call: public Command {
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
return script->function(_name)->call(this, script->replacevars(_args), return script->function(log, _name)->call(log, this, script->replacevars(_args),
script, frame); script, frame);
} }
public: public:
QString _name; QString _name;
@ -2178,28 +2189,28 @@ class If: public Command {
+selector+" "+_cmp+" "+value); +selector+" "+_cmp+" "+value);
} else { } else {
switch (_cmp[0].toLatin1()) { switch (_cmp[0].toLatin1()) {
case '=': check = script->variable(_variable)==value; case '=': check = script->variable(log, _variable)==value;
break; break;
case '!': check = script->variable(_variable)!=value; case '!': check = script->variable(log, _variable)!=value;
break; break;
case '.': check = script->variable(_variable).contains(value); case '.': check = script->variable(log, _variable).contains(value);
break; break;
case '^': check = !script->variable(_variable).contains(value); case '^': check = !script->variable(log, _variable).contains(value);
break; break;
case '~': check = case '~': check =
script->variable(_variable).contains(QRegularExpression(value)); script->variable(log, _variable).contains(QRegularExpression(value));
break; break;
case '<': check = script->variable(_variable).toInt()<value.toInt(); case '<': check = script->variable(log, _variable).toInt()<value.toInt();
break; break;
case '>': check = script->variable(_variable).toInt()>value.toInt(); case '>': check = script->variable(log, _variable).toInt()>value.toInt();
break; break;
default:; default:;
} }
log(QString("evaluated expression to ")+(check?"true":"false")+": " log(QString("evaluated expression to ")+(check?"true":"false")+": "
+script->variable(_variable)+" "+_cmp+" "+value); +script->variable(log, _variable)+" "+_cmp+" "+value);
} }
if (check) return runScript(this, _script, script, frame); if (check) return runScript(log, this, _script, script, frame);
else if (_else) return runScript(this, _else, script, frame); else if (_else) return runScript(log, this, _else, script, frame);
return true; return true;
} }
private: private:
@ -2332,7 +2343,7 @@ class Check: public Command {
default:; default:;
} }
log("evaluated expression: "+value1+" "+_cmp+" "+value2); log("evaluated expression: "+value1+" "+_cmp+" "+value2);
if (!check) throw CheckFailed(value1, _cmp, value2); if (!check) error(log, CheckFailed(value1, _cmp, value2));
return true; return true;
} }
private: private:
@ -2379,8 +2390,8 @@ class For: public Command {
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
Q_FOREACH(QString i, _vals.size()?_vals:commaSeparatedList(script->variable(_variable))) { Q_FOREACH(QString i, _vals.size()?_vals:commaSeparatedList(script->variable(log, _variable))) {
if (!runScript(this, _script, script, frame, QStringList()<<_variable, QStringList()<<i)) if (!runScript(log, this, _script, script, frame, QStringList()<<_variable, QStringList()<<i))
return false; return false;
} }
return true; return true;
@ -2444,7 +2455,7 @@ class OfflineStoragePath: public Command {
Logger log(this, script); Logger log(this, script);
QDir path(_path); QDir path(_path);
if (!path.exists() && !path.mkpath(_path)) if (!path.exists() && !path.mkpath(_path))
throw DirectoryCannotBeCreated(_path); error(log, DirectoryCannotBeCreated(_path));
TestWebPage* page(dynamic_cast<TestWebPage*>(frame->page())); TestWebPage* page(dynamic_cast<TestWebPage*>(frame->page()));
page->settings()->setOfflineStoragePath(_path); page->settings()->setOfflineStoragePath(_path);
return true; return true;
@ -2513,16 +2524,18 @@ class Include: public Command {
try { try {
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = std::shared_ptr<Script>(new Script);
cmd->_script->parse(txt.split('\n'), cmd->_filename, 1, indent+1); cmd->_script->parse(txt.split('\n'), cmd->_filename, 1, indent+1);
} catch (std::exception& e) { } catch (Exception& e) {
throw ParseIncludeFailed(cmd->_filename, e.what()); throw ParseIncludeFailed(cmd->_filename, e.what());
} }
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame* frame) try { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
return runScript(this, _script, script, frame); try {
} catch (std::exception& e) { return runScript(log, this, _script, script, frame);
throw ExecuteIncludeFailed(_filename, e.what()); } catch (Exception& e) {
error(log, ExecuteIncludeFailed(_filename, e.what()));
}
} }
private: private:
QString _filename; QString _filename;
@ -2624,27 +2637,27 @@ class Case: public Command {
+selector+" "+condition.cmp+" "+value); +selector+" "+condition.cmp+" "+value);
} else { } else {
switch (condition.cmp[0].toLatin1()) { switch (condition.cmp[0].toLatin1()) {
case '=': check = script->variable(_variable)==value; case '=': check = script->variable(log, _variable)==value;
break; break;
case '!': check = script->variable(_variable)!=value; case '!': check = script->variable(log, _variable)!=value;
break; break;
case '.': check = script->variable(_variable).contains(value); case '.': check = script->variable(log, _variable).contains(value);
break; break;
case '^': check = !script->variable(_variable).contains(value); case '^': check = !script->variable(log, _variable).contains(value);
break; break;
case '~': check = case '~': check =
script->variable(_variable).contains(QRegularExpression(value)); script->variable(log, _variable).contains(QRegularExpression(value));
break; break;
case '<': check = script->variable(_variable).toInt()<value.toInt(); case '<': check = script->variable(log, _variable).toInt()<value.toInt();
break; break;
case '>': check = script->variable(_variable).toInt()>value.toInt(); case '>': check = script->variable(log, _variable).toInt()>value.toInt();
break; break;
default:; default:;
} }
log(QString("evaluated expression to ")+(check?"true":"false")+": " log(QString("evaluated expression to ")+(check?"true":"false")+": "
+script->variable(_variable)+" "+condition.cmp+" "+value); +script->variable(log, _variable)+" "+condition.cmp+" "+value);
} }
if (check) return runScript(this, condition.script, script, frame); if (check) return runScript(log, this, condition.script, script, frame);
} }
return true; return true;
} }
@ -2684,7 +2697,7 @@ class Fail: public Command {
} }
bool execute(Script* script, QWebFrame*) { bool execute(Script* script, QWebFrame*) {
Logger log(this, script); Logger log(this, script);
throw TestFailed(script->replacevars(_text)); error(log, TestFailed(script->replacevars(_text)));
return true; // dummy return true; // dummy
} }
private: private:
@ -2725,7 +2738,7 @@ inline bool Screenshot::execute(Script* script, QWebFrame* frame) {
log("screenshots disabled"); log("screenshots disabled");
return true; return true;
} }
QString filename(screenshot(line(), script->targetdir(), QString filename(screenshot(log, line(), script->targetdir(),
script->testclass(), script->testclass(),
script->replacevars(_filename), frame)); script->replacevars(_filename), frame));
log["[[ATTACHMENT|"+filename+"]]"]; log["[[ATTACHMENT|"+filename+"]]"];
@ -2734,26 +2747,30 @@ inline bool Screenshot::execute(Script* script, QWebFrame* frame) {
inline Logger::Logger(Command* command, Script* script, bool showLines): inline Logger::Logger(Command* command, Script* script, bool showLines):
_command(command), _script(script) { _command(command), _script(script) {
_previous = _script->command(); if (command) {
_script->command(command); _previous = _script->command();
if (_command->log()) _script->command(command);
if (showLines) if (_command->log())
_script->log("\\ "+_command->command(), _command); if (showLines)
else _script->log("\\ "+_command->command(), _command);
_script->log("\\ "+_command->command().split('\n').first(), _command); else
_script->log("\\ "+_command->command().split('\n').first(), _command);
}
} }
inline void Logger::operator()(QString txt) { inline void Logger::operator()(QString txt) {
if (_command->log()) _script->log(" "+txt, _command); if (!_command || _command->log()) _script->log(" "+txt, _command);
} }
inline void Logger::operator[](QString txt) { inline void Logger::operator[](QString txt) {
_script->plainlog(txt); _script->plainlog(txt);
} }
inline Logger::~Logger() { inline Logger::~Logger() {
if (_command->log()) _script->log("/ "+_command->tag(), _command); if (_command) {
_script->command(_previous); if (_command->log()) _script->log("/ "+_command->tag(), _command);
_script->command(_previous);
}
} }
inline bool Command::runScript(Command* parentCommand, inline bool Command::runScript(Logger& log, Command* parentCommand,
std::shared_ptr<Script> script, std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
QStringList vars, QStringList vars,
@ -2761,7 +2778,7 @@ inline bool Command::runScript(Command* parentCommand,
Script scriptCopy(*script); // only work with a copy of script Script scriptCopy(*script); // only work with a copy of script
scriptCopy.set(*parent); scriptCopy.set(*parent);
if (args.size()!=vars.size()) if (args.size()!=vars.size())
throw WrongNumberOfArguments(vars, args); error(log, WrongNumberOfArguments(vars, args));
for (QStringList::iterator var(vars.begin()), arg(args.begin()); for (QStringList::iterator var(vars.begin()), arg(args.begin());
var<vars.end() && arg<args.end(); ++var, ++arg) { var<vars.end() && arg<args.end(); ++var, ++arg) {
parent->log("argument: "+*var+" = "+parent->replacevars(*arg), parent->log("argument: "+*var+" = "+parent->replacevars(*arg),
@ -2778,13 +2795,13 @@ inline bool Command::runScript(Command* parentCommand,
parent, SLOT(parentlog(QString))); parent, SLOT(parentlog(QString)));
parentCommand->_result = scriptCopy.result(); parentCommand->_result = scriptCopy.result();
Q_FOREACH(QString key, scriptCopy.variables()) // copy new variables to parent Q_FOREACH(QString key, scriptCopy.variables()) // copy new variables to parent
if (!vars.contains(key)) parent->set(key, scriptCopy.variable(key)); if (!vars.contains(key)) parent->set(key, scriptCopy.variable(log, key));
Q_FOREACH(QString key, scriptCopy.functions()) // copy new functions to parent Q_FOREACH(QString key, scriptCopy.functions()) // copy new functions to parent
parent->function(key, scriptCopy.function(key)); parent->function(key, scriptCopy.function(log, key));
if (parentCommand->_result.size()) if (parentCommand->_result.size())
parent->log("result: "+parentCommand->_result); parent->log("result: "+parentCommand->_result);
return res; return res;
} catch (const std::exception& x) { } catch (const Exception& x) {
parent->addSignals(frame); parent->addSignals(frame);
disconnect(&scriptCopy, SIGNAL(logging(QString)), disconnect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(parentlog(QString))); parent, SLOT(parentlog(QString)));

Loading…
Cancel
Save