From 332db8b079e97cb01ae7a51f5ef2bf3cdd30efc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?=
Date: Thu, 30 Apr 2015 14:25:24 +0000
Subject: [PATCH] More features: have a seperate setup script, where global
variable replacements can be placed, new commandline parameters, command
window, better recording, chose click type, ...
---
configure.ac | 2 +
docker/Dockerfile | 15 ++
docker/runtests.sh | 11 ++
src/commands.hxx | 348 ++++++++++++++++++++++++++++++++++++---------
src/testgui.hxx | 261 ++++++++++++++++++++++++----------
src/testgui.ui | 122 +++++++++++++---
src/webrunner.cxx | 2 +-
src/webtester.cxx | 9 +-
8 files changed, 603 insertions(+), 167 deletions(-)
create mode 100644 docker/Dockerfile
create mode 100755 docker/runtests.sh
diff --git a/configure.ac b/configure.ac
index 620efd9..99b3013 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,6 +29,8 @@ if test -z "${QMAKE}"; then
AC_MSG_ERROR([cannot find a qmake command])
fi
+# requires mrw-c++ - to be defined ...
+
README=$(tail -n +3 README)
README_DEB=$(tail -n +3 README | sed -e 's/^$/./g' -e 's/^/ /g')
DESCRIPTION=$(head -1 README)
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..36516cb
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,15 @@
+FROM ubuntu:latest
+MAINTAINER "Marc Wäckerlin"
+
+RUN apt-get install -y wget software-properties-common apt-transport-https
+RUN apt-add-repository https://dev.marc.waeckerlin.org/repository
+RUN wget -O- https://dev.marc.waeckerlin.org/repository/PublicKey | apt-key add -
+RUN apt-get update -y
+RUN apt-get install -y xvfb webtester
+
+ADD runtests.sh runtests.sh
+
+VOLUME /tests
+
+WORKDIR /tests
+CMD /runtests.sh
diff --git a/docker/runtests.sh b/docker/runtests.sh
new file mode 100755
index 0000000..a027708
--- /dev/null
+++ b/docker/runtests.sh
@@ -0,0 +1,11 @@
+#!/bin/bash -e
+
+if test -z "${WEBRUNNER_SCRIPTS}"; then
+ echo '*** ERROR: set at least -e WEBRUNNER_SCRIPTS="testfile.wt ..."'
+ echo " optional variables: XVFB_SERVER_ARGS, WEBRUNNER_ARGS"
+ exit 1
+fi
+
+xvfb-run -a --server-args="${XVFB_SERVER_ARGS:--screen 0 2048x2048x24}" \
+ webrunner ${WEBRUNNER_ARGS:--W 2048 -H 2048 -sx testoutput.xml} \
+ ${WEBRUNNER_SCRIPTS}
diff --git a/src/commands.hxx b/src/commands.hxx
index f685d0a..35ebb29 100644
--- a/src/commands.hxx
+++ b/src/commands.hxx
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
")
+ .replace("\n", "
")
+ +"
";
+ } break;
+ }
return cmds.trimmed();
}
void reset() {
@@ -368,6 +412,14 @@ class Script: public QObject {
_ignores.clear();
_cout.clear();
_cerr.clear();
+ _ignoreSignalsUntil.clear();
+ }
+ void cleanup() {
+ reset();
+ _variables.clear();
+ _rvariables.clear();
+ _timeout = 20;
+ _clicktype = JAVASCRIPT_CLICK;
}
std::shared_ptr parse(QStringList& in, int linenr) try {
QString line(in.takeFirst().trimmed());
@@ -555,19 +607,36 @@ class Script: public QObject {
}
void set(QString name, QString value) {
_variables[name] = value;
+ _rvariables[value] = name;
}
void unset(QString name) {
+ _rvariables.remove(_variables[name]);
_variables.remove(name);
}
void timeout(int t) {
_timeout = t;
}
+ void clicktype(ClickType c) {
+ _clicktype = c;
+ }
+ ClickType clicktype() {
+ return _clicktype;
+ }
QString replacevars(QString txt) {
for(QMap::iterator it(_variables.begin());
it!=_variables.end(); ++it)
txt.replace(it.key(), it.value());
return txt;
}
+ QString insertvars(QString txt) {
+ QMapIterator it(_rvariables);
+ it.toBack();
+ while (it.hasPrevious()) {
+ it.previous();
+ txt.replace(it.key(), it.value());
+ }
+ return txt;
+ }
public Q_SLOTS:
void log(QString text) {
text = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss ")+text;
@@ -703,8 +772,10 @@ class Script: public QObject {
QString _cerr;
bool _screenshots;
QString _ignoreSignalsUntil;
- QMap _variables;
+ QMap _variables; ///< variable mapping
+ QMap _rvariables; ///< reverse variable mapping
int _timeout;
+ ClickType _clicktype;
};
class Do: public Command {
@@ -714,7 +785,7 @@ class Do: public Command {
}
QString description() const {
return
- "do \n \n "
+ tag()+" \n \n "
"\n\n"
"Execute JavaScript on a CSS selected object. The object is the first "
"object in the DOM tree that matches the given CSS selector. You can "
@@ -723,7 +794,7 @@ class Do: public Command {
"one space";
}
QString command() const {
- return "do "+_selector+_javascript;
+ return tag()+" "+_selector+_javascript;
}
std::shared_ptr parse(Script*, QString args,
QStringList& in, int) {
@@ -735,8 +806,9 @@ class Do: public Command {
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
- QWebElement element(find(frame, _selector));
- if (element.isNull()) throw ElementNotFound(_selector);
+ QWebElement element(find(frame, script->replacevars(_selector)));
+ if (element.isNull())
+ throw ElementNotFound(script->replacevars(_selector));
_result =
element.evaluateJavaScript(script->replacevars(_javascript)).toString();
return true;
@@ -753,12 +825,12 @@ class Load: public Command {
}
QString description() const {
return
- "load "
+ tag()+" "
"\n\n"
"Load an URL, the URL is given as parameter in full syntax.";
}
QString command() const {
- return "load "+_url;
+ return tag()+" "+_url;
}
std::shared_ptr parse(Script*, QString args, QStringList&, int) {
std::shared_ptr cmd(new Load());
@@ -781,7 +853,7 @@ class Expect: public Command {
}
QString description() const {
return
- "expect []"
+ tag()+" []"
"\n\n"
"Expect a signal. Signals are emitted by webkit and may contain "
"parameter. If a parameter is given in the script, then the parameter "
@@ -800,7 +872,7 @@ class Expect: public Command {
" - loadFinished true";
}
QString command() const {
- return "expect "+_signal._signal
+ return tag()+" "+_signal._signal
+(_signal._args.size()?" "+_signal._args.join(' '):QString());
}
std::shared_ptr parse(Script*, QString args, QStringList&, int) {
@@ -851,12 +923,12 @@ class Open: public Command {
}
QString description() const {
return
- "open"
+ tag()+
"\n\n"
"Open the browser window, so you can follow the test steps visually.";
}
QString command() const {
- return "open";
+ return tag();
}
std::shared_ptr parse(Script*, QString, QStringList&, int) {
std::shared_ptr cmd(new Open());
@@ -876,14 +948,14 @@ class Sleep: public Command {
}
QString description() const {
return
- "sleep "
+ tag()+" "
"\n\n"
"Sleep for a certain amount of seconds. This helps, if you must wait "
"for some javascript actions, i.e. AJAX or slow pages, and the "
"excpeted signals are not sufficient.";
}
QString command() const {
- return "sleep "+_time;
+ return tag()+" "+_time;
}
std::shared_ptr parse(Script*, QString time, QStringList&, int) {
std::shared_ptr cmd(new Sleep());
@@ -913,14 +985,14 @@ class Exit: public Command {
}
QString description() const {
return
- "exit"
+ tag()+
"\n\n"
"Successfully terminate script immediately. The following commands "
"are not executed. This helps when you debug your scripts and you "
"want the script stop at a certain point for investigations.";
}
QString command() const {
- return "exit";
+ return tag();
}
std::shared_ptr parse(Script*, QString, QStringList&, int) {
std::shared_ptr cmd(new Exit());
@@ -939,7 +1011,7 @@ class IgnoreTo: public Command {
}
QString description() const {
return
- "ignoreto