more improve expect load; better logging in case of exception
This commit is contained in:
237
src/commands.hxx
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)));
|
||||||
|
Reference in New Issue
Block a user