cursor follows files and lines; javascript interaction to be handled later
This commit is contained in:
@@ -448,7 +448,7 @@ class Script: public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void logging(QString);
|
void logging(QString);
|
||||||
void progress(QString, int, int);
|
void progress(QString, int, int, int);
|
||||||
public:
|
public:
|
||||||
typedef std::pair<QString, QStringList> Signal;
|
typedef std::pair<QString, QStringList> Signal;
|
||||||
enum ClickType {
|
enum ClickType {
|
||||||
@@ -640,8 +640,7 @@ class Script: public QObject {
|
|||||||
int retries(0), back(0);
|
int retries(0), back(0);
|
||||||
for (auto cmd(_script.begin()); cmd!=_script.end();
|
for (auto cmd(_script.begin()); cmd!=_script.end();
|
||||||
_step+=(*cmd)->steps(this), ++cmd) {
|
_step+=(*cmd)->steps(this), ++cmd) {
|
||||||
progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()),
|
progress((*cmd)->file(), (*cmd)->line(), _step, countSteps());
|
||||||
_step, countSteps());
|
|
||||||
xml::Node testcase("testcase");
|
xml::Node testcase("testcase");
|
||||||
try {
|
try {
|
||||||
testcase.attr("classname") =
|
testcase.attr("classname") =
|
||||||
@@ -672,8 +671,7 @@ class Script: public QObject {
|
|||||||
_testsuites->last()<<testcase;
|
_testsuites->last()<<testcase;
|
||||||
break; // test is successfully finished
|
break; // test is successfully finished
|
||||||
}
|
}
|
||||||
progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()),
|
progress((*cmd)->file(), (*cmd)->line(), _step, countSteps());
|
||||||
_step, countSteps());
|
|
||||||
} catch (PossibleRetryLoad& e) {
|
} catch (PossibleRetryLoad& e) {
|
||||||
_timer.stop();
|
_timer.stop();
|
||||||
// timeout may happen during load due to bad internet connection
|
// timeout may happen during load due to bad internet connection
|
||||||
@@ -777,7 +775,7 @@ class Script: public QObject {
|
|||||||
}
|
}
|
||||||
removeSignals(frame);
|
removeSignals(frame);
|
||||||
if (!_signals.empty()) error(UnhandledSignals(_signals));
|
if (!_signals.empty()) error(UnhandledSignals(_signals));
|
||||||
progress("success", 0, 0);
|
progress(QString(), 0, 0, 0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
std::shared_ptr<Command> command() {
|
std::shared_ptr<Command> command() {
|
||||||
@@ -1074,8 +1072,8 @@ class Script: public QObject {
|
|||||||
_prototypes[c->tag()] = std::shared_ptr<Command>(c);
|
_prototypes[c->tag()] = std::shared_ptr<Command>(c);
|
||||||
}
|
}
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void innerProgress(QString txt, int delta) {
|
void innerProgress(QString file, int line, int delta) {
|
||||||
progress(txt, _step+delta, countSteps());
|
progress(file, line, _step+delta, countSteps());
|
||||||
}
|
}
|
||||||
void authenticationRequired(QNetworkReply*, QAuthenticator* a) {
|
void authenticationRequired(QNetworkReply*, QAuthenticator* a) {
|
||||||
if (_auth.contains(a->realm())) {
|
if (_auth.contains(a->realm())) {
|
||||||
@@ -3211,13 +3209,13 @@ inline bool Command::runScript(Logger& log, Command* parentCommand,
|
|||||||
try {
|
try {
|
||||||
assert(connect(&scriptCopy, SIGNAL(logging(QString)),
|
assert(connect(&scriptCopy, SIGNAL(logging(QString)),
|
||||||
parent, SLOT(parentlog(QString))));
|
parent, SLOT(parentlog(QString))));
|
||||||
assert(connect(&scriptCopy, SIGNAL(progress(QString, int, int)),
|
assert(connect(&scriptCopy, SIGNAL(progress(QString, int, int, int)),
|
||||||
parent, SLOT(innerProgress(QString, int))));
|
parent, SLOT(innerProgress(QString, int, int))));
|
||||||
parent->removeSignals(frame);
|
parent->removeSignals(frame);
|
||||||
bool res(scriptCopy.run(frame));
|
bool res(scriptCopy.run(frame));
|
||||||
parent->addSignals(frame);
|
parent->addSignals(frame);
|
||||||
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int)),
|
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int, int)),
|
||||||
parent, SLOT(innerProgress(QString, int)));
|
parent, SLOT(innerProgress(QString, int, int)));
|
||||||
disconnect(&scriptCopy, SIGNAL(logging(QString)),
|
disconnect(&scriptCopy, SIGNAL(logging(QString)),
|
||||||
parent, SLOT(parentlog(QString)));
|
parent, SLOT(parentlog(QString)));
|
||||||
parentCommand->_result = scriptCopy.result();
|
parentCommand->_result = scriptCopy.result();
|
||||||
@@ -3229,8 +3227,8 @@ inline bool Command::runScript(Logger& log, Command* parentCommand,
|
|||||||
return res;
|
return res;
|
||||||
} catch (const Exception& x) {
|
} catch (const Exception& x) {
|
||||||
parent->addSignals(frame);
|
parent->addSignals(frame);
|
||||||
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int)),
|
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int, int)),
|
||||||
parent, SLOT(innerProgress(QString, int)));
|
parent, SLOT(innerProgress(QString, int, int)));
|
||||||
disconnect(&scriptCopy, SIGNAL(logging(QString)),
|
disconnect(&scriptCopy, SIGNAL(logging(QString)),
|
||||||
parent, SLOT(parentlog(QString)));
|
parent, SLOT(parentlog(QString)));
|
||||||
throw;
|
throw;
|
||||||
|
@@ -87,6 +87,11 @@ class CodeEditor: public QPlainTextEdit {
|
|||||||
updateLineNumberAreaWidth(0);
|
updateLineNumberAreaWidth(0);
|
||||||
highlightCurrentLine();
|
highlightCurrentLine();
|
||||||
}
|
}
|
||||||
|
void gotoLine(int line) {
|
||||||
|
QTextCursor cursor(document()->findBlockByNumber(line-1));
|
||||||
|
setTextCursor(cursor);
|
||||||
|
highlightCurrentLine();
|
||||||
|
}
|
||||||
void lineNumberAreaPaintEvent(QPaintEvent *event) {
|
void lineNumberAreaPaintEvent(QPaintEvent *event) {
|
||||||
QPainter painter(lineNumberArea);
|
QPainter painter(lineNumberArea);
|
||||||
painter.fillRect(event->rect(), Qt::lightGray);
|
painter.fillRect(event->rect(), Qt::lightGray);
|
||||||
|
@@ -16,6 +16,7 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
|||||||
void include(QString);
|
void include(QString);
|
||||||
void close(ScriptFile*);
|
void close(ScriptFile*);
|
||||||
void run(const QString&, const QString&, bool, Script&);
|
void run(const QString&, const QString&, bool, Script&);
|
||||||
|
void running(QString file, int line);
|
||||||
public:
|
public:
|
||||||
ScriptFile(QWidget* p = nullptr): QDockWidget(p) {
|
ScriptFile(QWidget* p = nullptr): QDockWidget(p) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
@@ -39,6 +40,9 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
|||||||
setWindowTitle(name+"[*]");
|
setWindowTitle(name+"[*]");
|
||||||
setWindowModified(false);
|
setWindowModified(false);
|
||||||
}
|
}
|
||||||
|
void gotoLine(int line) {
|
||||||
|
_editor->gotoLine(line);
|
||||||
|
}
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void load(QString name = QString()) {
|
void load(QString name = QString()) {
|
||||||
if (isWindowModified() &&
|
if (isWindowModified() &&
|
||||||
@@ -113,7 +117,10 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
|||||||
_run->setEnabled(false);
|
_run->setEnabled(false);
|
||||||
Script script;
|
Script script;
|
||||||
try {
|
try {
|
||||||
assert(connect(&script, SIGNAL(progress(QString, int, int)), SLOT(progress(QString, int, int))));
|
assert(connect(&script, SIGNAL(progress(QString, int, int, int)),
|
||||||
|
SLOT(progress(QString, int, int, int))));
|
||||||
|
assert(connect(&script, SIGNAL(progress(QString, int, int, int)),
|
||||||
|
SIGNAL(running(QString, int))));
|
||||||
QString text(_editor->textCursor().selection().toPlainText());
|
QString text(_editor->textCursor().selection().toPlainText());
|
||||||
if (text.isEmpty()) text = _editor->toPlainText();
|
if (text.isEmpty()) text = _editor->toPlainText();
|
||||||
run(_name, text, _screenshots->isChecked(), script);
|
run(_name, text, _screenshots->isChecked(), script);
|
||||||
@@ -218,8 +225,8 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
|||||||
_editor->moveCursor(QTextCursor::End);
|
_editor->moveCursor(QTextCursor::End);
|
||||||
_editor->ensureCursorVisible();
|
_editor->ensureCursorVisible();
|
||||||
}
|
}
|
||||||
void progress(const QString& txt, int pos, int max) {
|
void progress(const QString& file, int line, int pos, int max) {
|
||||||
_progress->setFormat(QString("%1 — %p%").arg(txt));
|
_progress->setFormat(QString("%1:%2 — %p%").arg(file).arg(line));
|
||||||
_progress->setMinimum(0);
|
_progress->setMinimum(0);
|
||||||
_progress->setMaximum(max);
|
_progress->setMaximum(max);
|
||||||
_progress->setValue(pos);
|
_progress->setValue(pos);
|
||||||
|
@@ -51,6 +51,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
|||||||
QSettings settings("mrw", "webtester");
|
QSettings settings("mrw", "webtester");
|
||||||
restoreGeometry(settings.value("geometry").toByteArray());
|
restoreGeometry(settings.value("geometry").toByteArray());
|
||||||
restoreState(settings.value("windowstate").toByteArray());
|
restoreState(settings.value("windowstate").toByteArray());
|
||||||
|
_actionCursorFollowsFiles->setChecked(settings.value("cursorfollowsfiles").toBool());
|
||||||
_url->completer()->setFilterMode(Qt::MatchContains);
|
_url->completer()->setFilterMode(Qt::MatchContains);
|
||||||
_url->completer()->setCaseSensitivity(Qt::CaseInsensitive);
|
_url->completer()->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
_url->completer()->setCompletionMode(QCompleter::PopupCompletion);
|
_url->completer()->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
@@ -238,15 +239,16 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
|||||||
_actionClear->setEnabled(active);
|
_actionClear->setEnabled(active);
|
||||||
_actionRun->setEnabled(active);
|
_actionRun->setEnabled(active);
|
||||||
}
|
}
|
||||||
void activate(QString name) {
|
QString activate(QString name) {
|
||||||
QFileInfo info(name);
|
QFileInfo info(name);
|
||||||
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
||||||
if (!_testscripts.contains(name)) return load(name);
|
if (!_testscripts.contains(name)) return load(name);
|
||||||
_testscripts[name]->show();
|
_testscripts[name]->show();
|
||||||
_testscripts[name]->raise();
|
_testscripts[name]->raise();
|
||||||
_testscripts[name]->activateWindow();
|
_testscripts[name]->activateWindow();
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
void load(QString name) {
|
QString load(QString name) {
|
||||||
QFileInfo info(name);
|
QFileInfo info(name);
|
||||||
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
||||||
if (_testscripts.contains(name)) try {
|
if (_testscripts.contains(name)) try {
|
||||||
@@ -260,13 +262,17 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
|||||||
assert(connect(_testscripts[name], SIGNAL(modified(ScriptFile*)), SLOT(modified(ScriptFile*))));
|
assert(connect(_testscripts[name], SIGNAL(modified(ScriptFile*)), SLOT(modified(ScriptFile*))));
|
||||||
assert(connect(_testscripts[name], SIGNAL(link(QString)), SLOT(activate(QString))));
|
assert(connect(_testscripts[name], SIGNAL(link(QString)), SLOT(activate(QString))));
|
||||||
assert(connect(_testscripts[name], SIGNAL(close(ScriptFile*)), SLOT(remove(ScriptFile*))));
|
assert(connect(_testscripts[name], SIGNAL(close(ScriptFile*)), SLOT(remove(ScriptFile*))));
|
||||||
assert(connect(_testscripts[name], SIGNAL(run(const QString&, const QString&, bool, Script&)), SLOT(run(const QString&, const QString&, bool, Script&))));
|
assert(connect(_testscripts[name], SIGNAL(run(const QString&, const QString&, bool, Script&)),
|
||||||
|
SLOT(run(const QString&, const QString&, bool, Script&))));
|
||||||
|
assert(connect(_testscripts[name], SIGNAL(running(QString, int)),
|
||||||
|
SLOT(showFileLine(QString, int))));
|
||||||
try {
|
try {
|
||||||
_testscripts[name]->load(name);
|
_testscripts[name]->load(name);
|
||||||
tabifyDockWidget(first, _testscripts[name]);
|
tabifyDockWidget(first, _testscripts[name]);
|
||||||
activate(name);
|
return activate(name);
|
||||||
} catch(const std::exception& x) {
|
} catch(const std::exception& x) {
|
||||||
remove(_testscripts[name]);
|
remove(_testscripts[name]);
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void remove(ScriptFile* scriptfile) {
|
void remove(ScriptFile* scriptfile) {
|
||||||
@@ -286,6 +292,14 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
|||||||
script.parse(text.split('\n'), name);
|
script.parse(text.split('\n'), name);
|
||||||
script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots);
|
script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots);
|
||||||
}
|
}
|
||||||
|
void showFileLine(QString file, int line) {
|
||||||
|
if (!_actionCursorFollowsFiles->isChecked() || file.isEmpty() || file=="setup") return;
|
||||||
|
try {
|
||||||
|
QString name(activate(file));
|
||||||
|
if (!name.isEmpty() && _testscripts.contains(name))
|
||||||
|
_testscripts[name]->gotoLine(line);
|
||||||
|
} catch (...) {} // ignore
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
ScriptFile* activeScriptFile(QWidget* focus=nullptr) {
|
ScriptFile* activeScriptFile(QWidget* focus=nullptr) {
|
||||||
//for (auto win: _testscripts) if (win->isActiveWindow()) return win;
|
//for (auto win: _testscripts) if (win->isActiveWindow()) return win;
|
||||||
@@ -298,6 +312,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
|||||||
QSettings settings("mrw", "webtester");
|
QSettings settings("mrw", "webtester");
|
||||||
settings.setValue("geometry", saveGeometry());
|
settings.setValue("geometry", saveGeometry());
|
||||||
settings.setValue("windowstate", saveState());
|
settings.setValue("windowstate", saveState());
|
||||||
|
settings.setValue("cursorfollowsfiles", _actionCursorFollowsFiles->isChecked());
|
||||||
if (isWindowModified() &&
|
if (isWindowModified() &&
|
||||||
QMessageBox::question(this, tr("Changes Not Saved"),
|
QMessageBox::question(this, tr("Changes Not Saved"),
|
||||||
tr("Leave without saving changes?"))
|
tr("Leave without saving changes?"))
|
||||||
|
@@ -133,7 +133,14 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="_actionCommands"/>
|
<addaction name="_actionCommands"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuOptions">
|
||||||
|
<property name="title">
|
||||||
|
<string>Options</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="_actionCursorFollowsFiles"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuOptions"/>
|
||||||
<addaction name="menuViews"/>
|
<addaction name="menuViews"/>
|
||||||
<addaction name="menuHelp"/>
|
<addaction name="menuHelp"/>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -648,6 +655,20 @@ this.dispatchEvent(evObj);</string>
|
|||||||
<string>&Commands ...</string>
|
<string>&Commands ...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="_actionCursorFollowsFiles">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cursor Follows Files</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>When running a script, the currently running file and line is highlighted. So the cursor follows the current file and line when running a script.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@@ -79,7 +79,9 @@ class TestWebPage: public QWebPage {
|
|||||||
if (_unattended) {
|
if (_unattended) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
return QWebPage::javaScriptAlert(frame, msg);
|
return;
|
||||||
|
/// @todo handle javascript alerts
|
||||||
|
//return QWebPage::javaScriptAlert(frame, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual bool javaScriptConfirm(QWebFrame* frame, const QString& msg) {
|
virtual bool javaScriptConfirm(QWebFrame* frame, const QString& msg) {
|
||||||
@@ -87,7 +89,9 @@ class TestWebPage: public QWebPage {
|
|||||||
if (_unattended) {
|
if (_unattended) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return QWebPage::javaScriptConfirm(frame, msg);
|
return true;
|
||||||
|
/// @todo handle javascript confirmations
|
||||||
|
//return QWebPage::javaScriptConfirm(frame, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void javaScriptConsoleMessage(const QString& msg,
|
virtual void javaScriptConsoleMessage(const QString& msg,
|
||||||
@@ -96,7 +100,9 @@ class TestWebPage: public QWebPage {
|
|||||||
if (_unattended) {
|
if (_unattended) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
return QWebPage::javaScriptConsoleMessage(msg, line, src);
|
return;
|
||||||
|
/// @todo handle javascript console messages
|
||||||
|
//return QWebPage::javaScriptConsoleMessage(msg, line, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual bool javaScriptPrompt(QWebFrame* frame, const QString& msg,
|
virtual bool javaScriptPrompt(QWebFrame* frame, const QString& msg,
|
||||||
@@ -105,7 +111,9 @@ class TestWebPage: public QWebPage {
|
|||||||
if (_unattended) {
|
if (_unattended) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return QWebPage::javaScriptPrompt(frame, msg, defaultValue, result);
|
return true;
|
||||||
|
/// @todo handle javascript prompts
|
||||||
|
//return QWebPage::javaScriptPrompt(frame, msg, defaultValue, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user