click has an optional clicktype; do has an optional selector; better detection and handling of moo-tool (joomla3) elements

master
Marc Wäckerlin 9 years ago
parent d7ad9f38d6
commit f4a288f156
  1. 80
      src/commands.hxx
  2. 82
      src/testgui.hxx

@ -30,6 +30,45 @@
#include <cassert>
#include <xml-cxx/xml.hxx>
namespace std {
template<typename T> class optional {
private:
T* _opt;
bool _set;
public:
optional():
_opt(0), _set(false) {
}
optional(const T& other):
_opt(new T(other)), _set(true) {
}
~optional() {
if (_set) delete _opt;
}
optional& operator=(const T& other) {
if (_set) delete _opt;
_set = true;
_opt = new T(other);
return *this;
}
T* operator->() {
return _opt;
}
T& operator*() {
return *_opt;
}
const T* operator->() const {
return _opt;
}
const T& operator*() const {
return *_opt;
}
operator bool() const {
return _set;
}
};
}
class Script;
class Command;
class Function;
@ -878,7 +917,7 @@ class Do: public Command {
}
QString description() const {
return
tag()+" <selector>\n <javascript-line1>\n <javascript-line2>"
tag()+" [<selector>]\n <javascript-line1>\n <javascript-line2>"
"\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 "
@ -892,15 +931,18 @@ class Do: public Command {
std::shared_ptr<Command> parse(Script*, QString args,
QStringList& in, int) {
std::shared_ptr<Do> cmd(new Do());
cmd->_selector = args;
cmd->_selector = args.trimmed();
cmd->_javascript = subCommandBlock(in).join("\n");
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
QWebElement element(find(frame, script->replacevars(_selector)));
if (element.isNull())
throw ElementNotFound(script->replacevars(_selector));
QWebElement element(frame->documentElement());
if (_selector.size()) {
QWebElement element(find(frame, script->replacevars(_selector)));
if (element.isNull())
throw ElementNotFound(script->replacevars(_selector));
}
_result =
element.evaluateJavaScript(script->replacevars(_javascript)).toString();
return true;
@ -1454,32 +1496,43 @@ class Click: public Command {
}
QString description() const {
return
tag()+" <selector>"
tag()+" [<clicktype>] <selector>"
"\n\n"
"Click on the specified element";
"Click on the specified element. Either you explicitely specify a click"
" type, such as <realmouse> or <javascript>, or the previously set or"
" the default clicktype is used.";
}
QString command() const {
return tag()+" "+_selector;
return tag()+(_clicktype
?(*_clicktype==Script::REAL_MOUSE_CLICK?" realmouse"
:*_clicktype==Script::JAVASCRIPT_CLICK?" javascript":"")
:"")+" "+_selector;
}
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) {
std::shared_ptr<Click> cmd(new Click());
cmd->_selector = args;
if (args.trimmed().contains(QRegularExpression("^realmouse ")))
cmd->_clicktype = Script::REAL_MOUSE_CLICK;
else if (args.trimmed().contains(QRegularExpression("^javascript ")))
cmd->_clicktype = Script::JAVASCRIPT_CLICK;
cmd->_selector =
args.remove(QRegularExpression("^ *(realmouse|javascript) +"));
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
switch (script->clicktype()) {
QString clicktarget(script->replacevars(_selector));
switch (_clicktype ? *_clicktype : script->clicktype()) {
case Script::REAL_MOUSE_CLICK: {
log("Script::REAL_MOUSE_CLICK");
realMouseClick(frame, script->replacevars(_selector));
realMouseClick(frame, clicktarget);
break;
}
case Script::JAVASCRIPT_CLICK:
default: {
log("Script::JAVASCRIPT_CLICK");
QWebElement element(find(frame, script->replacevars(_selector)));
QWebElement element(find(frame, clicktarget));
if (element.isNull())
throw ElementNotFound(script->replacevars(_selector));
throw ElementNotFound(clicktarget);
_result = element.evaluateJavaScript("this.click();").toString();
break;
}
@ -1488,6 +1541,7 @@ class Click: public Command {
}
private:
QString _selector;
std::optional<Script::ClickType> _clicktype;
};
class Set: public Command {

@ -113,6 +113,8 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
}
void on__run_clicked() {
bool oldRecordState(_record->isChecked());
_record->setChecked(false);
_record->setEnabled(false);
_run->setEnabled(false);
try {
Script script;
@ -134,6 +136,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
.arg(x.what()));
}
_run->setEnabled(true);
_record->setEnabled(true);
_record->setChecked(oldRecordState);
}
void on__focused_clicked() {
@ -325,26 +328,9 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
_lastFocused=element;
if (_record->isChecked()) {
if (!element.isNull()) {
QString selected(selector(_lastFocused));
QRegularExpressionMatch mooCombo
(QRegularExpression("^(#jform_[_A-Za-z0-9]+)_chzn>.*$")
.match(selected));
QRegularExpressionMatch mooComboItem
(QRegularExpression
("^li\\.highlighted(\\.result-selected)?\\.active-result$")
.match(selected));
if (mooCombo.hasMatch()) {
// special treatment for moo tools combobox (e.g. used
// in joomla)
appendCommand("click "+map(mooCombo.captured(1)+">a"));
appendCommand("sleep "+map("1"));
} else if (mooComboItem.hasMatch()) {
// special treatment for item in moo tools combobox
appendCommand
("click "+map("li.active-result[data-option-array-index=\""
+element.attribute("data-option-array-index")
+"\"]"));
appendCommand("sleep "+map("1"));
QString selected(selector(element));
if (handleMooTools(_lastFocused)) {
// handled in handleMooTools
} else if (_lastFocused.tagName()=="SELECT") {
// click on a select results in a value change
// find all selected options ...
@ -356,15 +342,14 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
v += value(option);
}
setValue(selected, v);
} else {
appendCommand("click "+map(selected));
}
if (_lastFocused.tagName()=="TEXTAREA" ||
} else if (_lastFocused.tagName()=="TEXTAREA" ||
_lastFocused.tagName()=="INPUT" &&
_lastFocused.attribute("type")=="text") {
// user clickt in a text edit field, so not the klick
// is important, but the text that will be typed
_typing = true;
} else {
appendCommand("click "+map(selected));
}
} else {
appendCommand("# click, but where?");
@ -531,7 +516,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
void javascript(const QString& selector, QString code) {
if (_record->isChecked())
appendCommand("do "+map(selector)+"\n "
+map(code).replace("\n", "\\n"));
+map(code).replace("\n", "\n "));
}
void cleanup(const QString& selector) {
QString text(_testscript->toPlainText());
@ -565,6 +550,53 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
.join("', '")+"'"));
}
}
bool handleMooTools(QWebElement element) {
QString selected(selector(element));
QRegularExpressionMatch mooCombo
(QRegularExpression("^(#jform_[_A-Za-z0-9]+)_chzn>.*$")
.match(selected));
QRegularExpressionMatch mooComboItem
(QRegularExpression
("^li\\.highlighted(\\.result-selected)?\\.active-result$")
.match(selected));
if (mooCombo.hasMatch()) {
// special treatment for moo tools combobox (e.g. used
// in joomla)
appendCommand("click realmouse "+map(mooCombo.captured(1)+">a"));
appendCommand("sleep "+map("1"));
return true;
} else if (mooComboItem.hasMatch()) {
// special treatment for item in moo tools combobox
appendCommand
("click realmouse "+map("li.active-result[data-option-array-index=\""
+element.attribute("data-option-array-index")
+"\"]"));
appendCommand("sleep "+map("1"));
return true;
} else if (element.tagName()=="INPUT") {
for (QWebElement e(element); !(e=e.parent()).isNull();)
if (e.hasClass("chzn-container")) {
_lastFocused = e;
appendCommand("# moo tools combobox with search field");
appendCommand("# first set all elements visible");
javascript(map(selector(e)+" ul"),
"this.style.height = \"auto\";\n"
"this.style.maxHeight = \"auto\";\n"
"this.style.overflow = \"visible\"");
appendCommand("sleep "+map("1"));
appendCommand("# moo tools open combobox");
appendCommand("click realmouse "+map(selector(e)));
return true;
}
} else if (element.hasAttribute("id") && // is it a selected option?
element.attribute("id").contains("_chzn_o_")) {
appendCommand("# moo tools select item");
appendCommand("click realmouse "+map(selector(element)));
_lastFocused = element;
return true;
}
return false;
}
QString execute(const QString& selector, const QString& code) {
javascript(selector, code);
return _web->page()->mainFrame()->documentElement().findFirst(selector)

Loading…
Cancel
Save