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

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

@ -30,6 +30,45 @@
#include <cassert> #include <cassert>
#include <xml-cxx/xml.hxx> #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 Script;
class Command; class Command;
class Function; class Function;
@ -878,7 +917,7 @@ class Do: public Command {
} }
QString description() const { QString description() const {
return return
tag()+" <selector>\n <javascript-line1>\n <javascript-line2>" tag()+" [<selector>]\n <javascript-line1>\n <javascript-line2>"
"\n\n" "\n\n"
"Execute JavaScript on a CSS selected object. The object is the first " "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 " "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, std::shared_ptr<Command> parse(Script*, QString args,
QStringList& in, int) { QStringList& in, int) {
std::shared_ptr<Do> cmd(new Do()); std::shared_ptr<Do> cmd(new Do());
cmd->_selector = args; cmd->_selector = args.trimmed();
cmd->_javascript = subCommandBlock(in).join("\n"); cmd->_javascript = subCommandBlock(in).join("\n");
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
QWebElement element(frame->documentElement());
if (_selector.size()) {
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)); throw ElementNotFound(script->replacevars(_selector));
}
_result = _result =
element.evaluateJavaScript(script->replacevars(_javascript)).toString(); element.evaluateJavaScript(script->replacevars(_javascript)).toString();
return true; return true;
@ -1454,32 +1496,43 @@ class Click: public Command {
} }
QString description() const { QString description() const {
return return
tag()+" <selector>" tag()+" [<clicktype>] <selector>"
"\n\n" "\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 { 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<Command> parse(Script*, QString args, QStringList&, int) {
std::shared_ptr<Click> cmd(new Click()); 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; return cmd;
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
switch (script->clicktype()) { QString clicktarget(script->replacevars(_selector));
switch (_clicktype ? *_clicktype : script->clicktype()) {
case Script::REAL_MOUSE_CLICK: { case Script::REAL_MOUSE_CLICK: {
log("Script::REAL_MOUSE_CLICK"); log("Script::REAL_MOUSE_CLICK");
realMouseClick(frame, script->replacevars(_selector)); realMouseClick(frame, clicktarget);
break; break;
} }
case Script::JAVASCRIPT_CLICK: case Script::JAVASCRIPT_CLICK:
default: { default: {
log("Script::JAVASCRIPT_CLICK"); log("Script::JAVASCRIPT_CLICK");
QWebElement element(find(frame, script->replacevars(_selector))); QWebElement element(find(frame, clicktarget));
if (element.isNull()) if (element.isNull())
throw ElementNotFound(script->replacevars(_selector)); throw ElementNotFound(clicktarget);
_result = element.evaluateJavaScript("this.click();").toString(); _result = element.evaluateJavaScript("this.click();").toString();
break; break;
} }
@ -1488,6 +1541,7 @@ class Click: public Command {
} }
private: private:
QString _selector; QString _selector;
std::optional<Script::ClickType> _clicktype;
}; };
class Set: public Command { class Set: public Command {

@ -113,6 +113,8 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
} }
void on__run_clicked() { void on__run_clicked() {
bool oldRecordState(_record->isChecked()); bool oldRecordState(_record->isChecked());
_record->setChecked(false);
_record->setEnabled(false);
_run->setEnabled(false); _run->setEnabled(false);
try { try {
Script script; Script script;
@ -134,6 +136,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
.arg(x.what())); .arg(x.what()));
} }
_run->setEnabled(true); _run->setEnabled(true);
_record->setEnabled(true);
_record->setChecked(oldRecordState); _record->setChecked(oldRecordState);
} }
void on__focused_clicked() { void on__focused_clicked() {
@ -325,26 +328,9 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
_lastFocused=element; _lastFocused=element;
if (_record->isChecked()) { if (_record->isChecked()) {
if (!element.isNull()) { if (!element.isNull()) {
QString selected(selector(_lastFocused)); QString selected(selector(element));
QRegularExpressionMatch mooCombo if (handleMooTools(_lastFocused)) {
(QRegularExpression("^(#jform_[_A-Za-z0-9]+)_chzn>.*$") // handled in handleMooTools
.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"));
} else if (_lastFocused.tagName()=="SELECT") { } else if (_lastFocused.tagName()=="SELECT") {
// click on a select results in a value change // click on a select results in a value change
// find all selected options ... // find all selected options ...
@ -356,15 +342,14 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
v += value(option); v += value(option);
} }
setValue(selected, v); setValue(selected, v);
} else { } else if (_lastFocused.tagName()=="TEXTAREA" ||
appendCommand("click "+map(selected));
}
if (_lastFocused.tagName()=="TEXTAREA" ||
_lastFocused.tagName()=="INPUT" && _lastFocused.tagName()=="INPUT" &&
_lastFocused.attribute("type")=="text") { _lastFocused.attribute("type")=="text") {
// user clickt in a text edit field, so not the klick // user clickt in a text edit field, so not the klick
// is important, but the text that will be typed // is important, but the text that will be typed
_typing = true; _typing = true;
} else {
appendCommand("click "+map(selected));
} }
} else { } else {
appendCommand("# click, but where?"); appendCommand("# click, but where?");
@ -531,7 +516,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
void javascript(const QString& selector, QString code) { void javascript(const QString& selector, QString code) {
if (_record->isChecked()) if (_record->isChecked())
appendCommand("do "+map(selector)+"\n " appendCommand("do "+map(selector)+"\n "
+map(code).replace("\n", "\\n")); +map(code).replace("\n", "\n "));
} }
void cleanup(const QString& selector) { void cleanup(const QString& selector) {
QString text(_testscript->toPlainText()); QString text(_testscript->toPlainText());
@ -565,6 +550,53 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
.join("', '")+"'")); .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) { QString execute(const QString& selector, const QString& code) {
javascript(selector, code); javascript(selector, code);
return _web->page()->mainFrame()->documentElement().findFirst(selector) return _web->page()->mainFrame()->documentElement().findFirst(selector)

Loading…
Cancel
Save