|
|
|
@ -462,35 +462,45 @@ class Script: public QObject { |
|
|
|
|
linenr+=oldsize-in.size()) |
|
|
|
|
_script.push_back(parse(in, linenr)); |
|
|
|
|
} |
|
|
|
|
void run(QWebFrame* frame, QString td = QString(), bool screenshots = true, |
|
|
|
|
int maxretries = 0) { |
|
|
|
|
assert(_internalTestsuiteNode); |
|
|
|
|
run(frame, *_internalTestsuiteNode, td, |
|
|
|
|
screenshots, maxretries); //( @todo extract from parent
|
|
|
|
|
QStringList print() { |
|
|
|
|
QStringList result; |
|
|
|
|
for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd) { |
|
|
|
|
result += (*cmd)->command(); |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
void run(QWebFrame* frame) { |
|
|
|
|
run(frame, _testsuites, targetdir(), _screenshots, _maxretries); |
|
|
|
|
} |
|
|
|
|
void run(QWebFrame* frame, xml::Node& testsuiteNode, |
|
|
|
|
void run(QWebFrame* frame, std::shared_ptr<xml::Node> testsuites, |
|
|
|
|
QString td = QString(), bool screenshots = true, |
|
|
|
|
int maxretries = 0) { |
|
|
|
|
_internalTestsuiteNode = &testsuiteNode; |
|
|
|
|
assert(_internalTestsuiteNode); |
|
|
|
|
_testsuites = testsuites; |
|
|
|
|
_timeout = 20; // defaults to 20s
|
|
|
|
|
_ignoreSignalsUntil.clear(); |
|
|
|
|
addSignals(frame); |
|
|
|
|
_screenshots = screenshots; |
|
|
|
|
_maxretries = maxretries; |
|
|
|
|
_timer.setSingleShot(true); |
|
|
|
|
targetdir(!td.isEmpty() |
|
|
|
|
? td |
|
|
|
|
: _testsuites->children() |
|
|
|
|
? xmlstr(_testsuites->last().attr("name")) |
|
|
|
|
: "attachments"); |
|
|
|
|
if (!_testsuites->children()) { |
|
|
|
|
xml::Node testsuite("testsuite"); |
|
|
|
|
testsuite.attr("name") = "Unnamed Test Suite"; |
|
|
|
|
(*_testsuites)<<testsuite; |
|
|
|
|
} |
|
|
|
|
int retries(0), back(0); |
|
|
|
|
for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd) { |
|
|
|
|
xml::Node testcase("testcase"); |
|
|
|
|
try { |
|
|
|
|
testcase.attr("classname") = |
|
|
|
|
testsuiteNode.attr("name"); |
|
|
|
|
//xmlattr((*cmd)->command(), true).toStdString();
|
|
|
|
|
testcase.attr("classname") = xmlattr(_testclass, true).toStdString(); |
|
|
|
|
testcase.attr("name") =
|
|
|
|
|
xmlattr((*cmd)->tag(), true).toStdString(); |
|
|
|
|
xmlattr((*cmd)->command(), true).toStdString(); |
|
|
|
|
if (!_ignores.size() || (*cmd)->tag()=="label") { // not ignored
|
|
|
|
|
_timer.start(_timeout*1000); |
|
|
|
|
testsuite(xmlstr(testsuiteNode.attr("name"))); |
|
|
|
|
targetdir(!td.isEmpty() ? td : xmlstr(testsuiteNode.attr("name"))); |
|
|
|
|
try { |
|
|
|
|
if (!(*cmd)->execute(this, frame)) { |
|
|
|
|
_timer.stop(); |
|
|
|
@ -501,7 +511,7 @@ class Script: public QObject { |
|
|
|
|
xmlattr(_cerr).toStdString()); |
|
|
|
|
_cout.clear(); |
|
|
|
|
_cerr.clear(); |
|
|
|
|
testsuiteNode<<testcase; |
|
|
|
|
_testsuites->last()<<testcase; |
|
|
|
|
break; // test is successfully finished
|
|
|
|
|
} |
|
|
|
|
} catch (PossibleRetryLoad& e) { |
|
|
|
@ -511,7 +521,7 @@ class Script: public QObject { |
|
|
|
|
try { // take a screenshot on error
|
|
|
|
|
QString filename(Screenshot::screenshot |
|
|
|
|
((*cmd)->line(), targetdir(), |
|
|
|
|
QFileInfo(testsuite()).baseName(), |
|
|
|
|
_testclass, |
|
|
|
|
QString("retry-%1") |
|
|
|
|
.arg((ulong)retries, 2, 10, |
|
|
|
|
QLatin1Char('0')), |
|
|
|
@ -563,7 +573,7 @@ class Script: public QObject { |
|
|
|
|
xmlattr(_cerr).toStdString()); |
|
|
|
|
_cout.clear(); |
|
|
|
|
_cerr.clear(); |
|
|
|
|
testsuiteNode<<testcase; |
|
|
|
|
_testsuites->last()<<testcase; |
|
|
|
|
} |
|
|
|
|
} catch (Exception& e) { |
|
|
|
|
_timer.stop(); |
|
|
|
@ -574,7 +584,7 @@ class Script: public QObject { |
|
|
|
|
xmlattr(_cerr).toStdString()); |
|
|
|
|
_cout.clear(); |
|
|
|
|
_cerr.clear(); |
|
|
|
|
testsuiteNode<<testcase; |
|
|
|
|
_testsuites->last()<<testcase; |
|
|
|
|
removeSignals(frame); |
|
|
|
|
e.line((*cmd)->line()); |
|
|
|
|
if (screenshots) |
|
|
|
@ -582,22 +592,20 @@ class Script: public QObject { |
|
|
|
|
{ |
|
|
|
|
QString filename(Screenshot::sourceHtml |
|
|
|
|
((*cmd)->line(), targetdir(), |
|
|
|
|
QFileInfo(testsuite()).baseName(), |
|
|
|
|
_testclass, |
|
|
|
|
"error", frame)); |
|
|
|
|
plainlog("[[ATTACHMENT|"+filename+"]]"); |
|
|
|
|
} { |
|
|
|
|
QString filename(Screenshot::screenshot |
|
|
|
|
((*cmd)->line(), targetdir(), |
|
|
|
|
QFileInfo(testsuite()).baseName(), |
|
|
|
|
_testclass, |
|
|
|
|
"error", frame)); |
|
|
|
|
plainlog("[[ATTACHMENT|"+filename+"]]"); |
|
|
|
|
} |
|
|
|
|
} catch (... ) {} // ignore exception in screenshot
|
|
|
|
|
_internalTestsuiteNode = 0; |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_internalTestsuiteNode = 0; |
|
|
|
|
removeSignals(frame); |
|
|
|
|
if (!_signals.empty()) throw UnhandledSignals(_signals); |
|
|
|
|
} |
|
|
|
@ -613,18 +621,26 @@ class Script: public QObject { |
|
|
|
|
bool screenshots() { |
|
|
|
|
return _screenshots; |
|
|
|
|
} |
|
|
|
|
void testsuite(QString name) { |
|
|
|
|
_testsuite = name; |
|
|
|
|
} |
|
|
|
|
QString testsuite() { |
|
|
|
|
return _testsuite; |
|
|
|
|
} |
|
|
|
|
void targetdir(QString name) { |
|
|
|
|
_targetdir = name; |
|
|
|
|
} |
|
|
|
|
QString targetdir() { |
|
|
|
|
return _targetdir; |
|
|
|
|
} |
|
|
|
|
void testclass(QString tc) { |
|
|
|
|
_testclass = tc; |
|
|
|
|
} |
|
|
|
|
QString testclass() { |
|
|
|
|
return _testclass; |
|
|
|
|
} |
|
|
|
|
void testsuite(QString name) { |
|
|
|
|
xml::Node testsuite("testsuite"); |
|
|
|
|
testsuite.attr("name") = xmlattr(name, true).toStdString(); |
|
|
|
|
testsuite.attr("timestamp") = |
|
|
|
|
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString(); |
|
|
|
|
_testsuites->last().attr("failures") = "0"; |
|
|
|
|
(*_testsuites)<<testsuite; |
|
|
|
|
} |
|
|
|
|
Signal getSignal() { |
|
|
|
|
while (!_signals.size()) QCoreApplication::processEvents(); |
|
|
|
|
Signal res(_signals.front()); |
|
|
|
@ -655,10 +671,11 @@ class Script: public QObject { |
|
|
|
|
_rvariables = o._rvariables; |
|
|
|
|
_timeout = o._timeout; |
|
|
|
|
_clicktype = o._clicktype; |
|
|
|
|
_testsuite = o._testsuite; |
|
|
|
|
_internalTestsuiteNode = o._internalTestsuiteNode; |
|
|
|
|
assert(_internalTestsuiteNode); |
|
|
|
|
_testsuites = o._testsuites; |
|
|
|
|
_testclass = o._testclass; |
|
|
|
|
_targetdir = o._targetdir; |
|
|
|
|
_maxretries = o._maxretries; |
|
|
|
|
_screenshots = o._screenshots; |
|
|
|
|
_cout.clear(); |
|
|
|
|
_cerr.clear(); |
|
|
|
|
_ignoreSignalsUntil.clear(); |
|
|
|
@ -835,15 +852,16 @@ class Script: public QObject { |
|
|
|
|
QString _cout; |
|
|
|
|
QString _cerr; |
|
|
|
|
bool _screenshots; |
|
|
|
|
int _maxretries; |
|
|
|
|
QString _ignoreSignalsUntil; |
|
|
|
|
QMap<QString, QString> _variables; ///< variable mapping
|
|
|
|
|
QMap<LenString, LenString> _rvariables; ///< reverse variable mapping
|
|
|
|
|
QMap<QString, std::shared_ptr<Function> > _functions; |
|
|
|
|
int _timeout; |
|
|
|
|
ClickType _clicktype; |
|
|
|
|
QString _testsuite; |
|
|
|
|
QString _targetdir; |
|
|
|
|
xml::Node* _internalTestsuiteNode; ///< only valid within run
|
|
|
|
|
std::shared_ptr<xml::Node> _testsuites; ///< only valid within run
|
|
|
|
|
QString _testclass; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class Do: public Command { |
|
|
|
@ -1892,7 +1910,8 @@ class If: public Command { |
|
|
|
|
"Match allows a regular expression."; |
|
|
|
|
} |
|
|
|
|
QString command() const { |
|
|
|
|
return tag(); |
|
|
|
|
return tag()+" "+_variable+" "+QString(_cmp)+" "+_value |
|
|
|
|
+(_script.get()?"\n"+_script->print().join("\n "):""); |
|
|
|
|
} |
|
|
|
|
std::shared_ptr<Command> parse(Script*, QString args, |
|
|
|
|
QStringList& in, int) { |
|
|
|
@ -1934,6 +1953,64 @@ class If: public Command { |
|
|
|
|
std::shared_ptr<Script> _script; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class TestSuite: public Command { |
|
|
|
|
public: |
|
|
|
|
QString tag() const { |
|
|
|
|
return "testsuite"; |
|
|
|
|
} |
|
|
|
|
QString description() const { |
|
|
|
|
return |
|
|
|
|
tag()+" <name>" |
|
|
|
|
"\n\n" |
|
|
|
|
"Start a testsuite and give it a name."; |
|
|
|
|
} |
|
|
|
|
QString command() const { |
|
|
|
|
return tag()+" "+_name; |
|
|
|
|
} |
|
|
|
|
std::shared_ptr<Command> parse(Script*, QString args, |
|
|
|
|
QStringList&, int) { |
|
|
|
|
std::shared_ptr<TestSuite> cmd(new TestSuite()); |
|
|
|
|
cmd->_name = args; |
|
|
|
|
return cmd; |
|
|
|
|
} |
|
|
|
|
bool execute(Script* script, QWebFrame* frame) { |
|
|
|
|
Logger log(this, script); |
|
|
|
|
script->testsuite(script->replacevars(_name)); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
|
QString _name; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class TestCase: public Command { |
|
|
|
|
public: |
|
|
|
|
QString tag() const { |
|
|
|
|
return "testcase"; |
|
|
|
|
} |
|
|
|
|
QString description() const { |
|
|
|
|
return |
|
|
|
|
tag()+" <name>" |
|
|
|
|
"\n\n" |
|
|
|
|
"Start a testcase and give it a name."; |
|
|
|
|
} |
|
|
|
|
QString command() const { |
|
|
|
|
return tag()+" "+_name; |
|
|
|
|
} |
|
|
|
|
std::shared_ptr<Command> parse(Script*, QString args, |
|
|
|
|
QStringList&, int) { |
|
|
|
|
std::shared_ptr<TestCase> cmd(new TestCase()); |
|
|
|
|
cmd->_name = args; |
|
|
|
|
return cmd; |
|
|
|
|
} |
|
|
|
|
bool execute(Script* script, QWebFrame* frame) { |
|
|
|
|
Logger log(this, script); |
|
|
|
|
script->testclass(script->replacevars(_name)); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
|
QString _name; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/* Template:
|
|
|
|
|
class : public Command { |
|
|
|
|
public: |
|
|
|
@ -1965,7 +2042,7 @@ inline bool Screenshot::execute(Script* script, QWebFrame* frame) { |
|
|
|
|
if (!script->screenshots()) return true; |
|
|
|
|
Logger log(this, script); |
|
|
|
|
QString filename(screenshot(line(), script->targetdir(), |
|
|
|
|
QFileInfo(script->testsuite()).baseName(), |
|
|
|
|
script->testclass(), |
|
|
|
|
script->replacevars(_filename), frame)); |
|
|
|
|
log["[[ATTACHMENT|"+filename+"]]"]; |
|
|
|
|
return true; |
|
|
|
@ -2004,7 +2081,7 @@ inline void Command::subScript(std::shared_ptr<Script> script, |
|
|
|
|
connect(script.get(), SIGNAL(logging(QString)), |
|
|
|
|
parent, SLOT(log(QString))); |
|
|
|
|
parent->removeSignals(frame); |
|
|
|
|
script->run(frame, parent->targetdir()); |
|
|
|
|
script->run(frame); |
|
|
|
|
parent->addSignals(frame); |
|
|
|
|
disconnect(script.get(), SIGNAL(logging(QString)), |
|
|
|
|
parent, SLOT(log(QString))); |
|
|
|
@ -2042,6 +2119,8 @@ inline void Script::initPrototypes() { |
|
|
|
|
add(new Function); |
|
|
|
|
add(new Call); |
|
|
|
|
add(new If); |
|
|
|
|
add(new TestSuite); |
|
|
|
|
add(new TestCase); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|