cursor follows files and lines; javascript interaction to be handled later

master
Marc Wäckerlin 6 years ago
parent 9142588686
commit 7bdd4a46fe
  1. 26
      src/commands.hxx
  2. 5
      src/editor.hxx
  3. 13
      src/scriptfile.hxx
  4. 23
      src/testgui.hxx
  5. 21
      src/testgui.ui
  6. 16
      src/webpage.hxx

@ -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>&amp;Commands ...</string> <string>&amp;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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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:

Loading…
Cancel
Save