now, multi document editing works mostly as designed; unfortunately qt does not send an event when the visibility of a tab window changes
This commit is contained in:
@@ -1,23 +1,32 @@
|
||||
#ifndef __SCRIPTFILE__HXX
|
||||
#define __SCRIPTFILE__HXX
|
||||
|
||||
#include <commands.hxx>
|
||||
#include <ui_scriptfile.hxx>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
#include <QTextDocumentFragment>
|
||||
#include <cassert>
|
||||
|
||||
class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
||||
Q_OBJECT
|
||||
Q_SIGNALS:
|
||||
void modified(ScriptFile*);
|
||||
void link(QString);
|
||||
void include(QString);
|
||||
void close(ScriptFile*);
|
||||
void run(const QString&, const QString&, bool, Script&);
|
||||
public:
|
||||
ScriptFile(QWidget* p=0): QDockWidget(p) {
|
||||
ScriptFile(QWidget* p = nullptr): QDockWidget(p) {
|
||||
setupUi(this);
|
||||
assert(connect(_editor, SIGNAL(textChanged()), SLOT(modified())));
|
||||
assert(connect(_editor, SIGNAL(include(QString)), SIGNAL(include(QString))));
|
||||
assert(connect(_editor, SIGNAL(link(QString)), SIGNAL(link(QString))));
|
||||
_searchBar->hide();
|
||||
_replaceBar->hide();
|
||||
_pageBar->hide();
|
||||
_lineBar->hide();
|
||||
_progress->hide();
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
}
|
||||
CodeEditor* editor() {
|
||||
return _editor;
|
||||
@@ -30,10 +39,208 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
|
||||
setWindowTitle(name+"[*]");
|
||||
setWindowModified(false);
|
||||
}
|
||||
public Q_SLOTS:
|
||||
void load(QString name = QString()) {
|
||||
if (isWindowModified() &&
|
||||
QMessageBox::question(this, tr("Changes Not Saved"),
|
||||
tr("Load script without saving changes?"))
|
||||
!= QMessageBox::Yes)
|
||||
return;
|
||||
QString oldname(_name);
|
||||
if (!name.isEmpty()) _name = name;
|
||||
QFileInfo info(name);
|
||||
if (info.absoluteDir()==QDir::current()) _name = info.fileName();
|
||||
try {
|
||||
QFile file(_name);
|
||||
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
|
||||
throw std::runtime_error("file open failed");
|
||||
_editor->setPlainText(QString::fromUtf8(file.readAll()));
|
||||
if (file.error()!=QFileDevice::NoError)
|
||||
throw std::runtime_error("file read failed");
|
||||
setWindowTitle(_name+"[*]");
|
||||
setWindowModified(false);
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
} catch(const std::exception& x) {
|
||||
QMessageBox::critical(this, tr("Open Failed"),
|
||||
tr("Reading test script failed, %2. "
|
||||
"Cannot read test script from file %1.")
|
||||
.arg(_name).arg(x.what()));
|
||||
_name = oldname;
|
||||
}
|
||||
}
|
||||
void save(QString name = QString()) {
|
||||
QString oldname(_name);
|
||||
if (!name.isEmpty()) _name = name;
|
||||
QFile file(_name);
|
||||
try {
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
throw std::runtime_error("file open failed");
|
||||
QTextStream out(&file);
|
||||
out<<_editor->toPlainText();
|
||||
if (out.status()!=QTextStream::Ok)
|
||||
throw std::runtime_error(std::string("file write failed (")
|
||||
+char(out.status()+48)+")");
|
||||
setWindowModified(false);
|
||||
setWindowTitle(_name+"[*]");
|
||||
} catch(const std::exception& x) {
|
||||
QMessageBox::critical(this, tr("Save Failed"),
|
||||
tr("Saving test script failed, %2. "
|
||||
"Cannot write test script to file %1.")
|
||||
.arg(_name).arg(x.what()));
|
||||
_name = oldname;
|
||||
}
|
||||
}
|
||||
void clear() {
|
||||
if (isWindowModified() &&
|
||||
QMessageBox::question(this, tr("Changes Not Saved"),
|
||||
tr("Clear script without saving changes?"))
|
||||
!= QMessageBox::Yes)
|
||||
return;
|
||||
_editor->clear();
|
||||
setWindowModified(false);
|
||||
}
|
||||
void modified() {
|
||||
setWindowModified(true);
|
||||
modified(this);
|
||||
}
|
||||
void run() {
|
||||
_progress->reset();
|
||||
_progress->show();
|
||||
_status->setCurrentIndex(STATUS_RUNNING);
|
||||
bool oldRecordState(_record->isChecked());
|
||||
_record->setChecked(false);
|
||||
_record->setEnabled(false);
|
||||
_run->setEnabled(false);
|
||||
Script script;
|
||||
try {
|
||||
assert(connect(&script, SIGNAL(progress(QString, int, int)), SLOT(progress(QString, int, int))));
|
||||
QString text(_editor->textCursor().selection().toPlainText());
|
||||
if (text.isEmpty()) text = _editor->toPlainText();
|
||||
run(_name, text, _screenshots->isChecked(), script);
|
||||
_status->setCurrentIndex(STATUS_SUCCESS);
|
||||
} catch (std::exception &x) {
|
||||
_status->setCurrentIndex(STATUS_ERROR);
|
||||
std::shared_ptr<Command> cmd(script.command());
|
||||
if (cmd)
|
||||
QMessageBox::critical(this,
|
||||
tr("Test Failed"),
|
||||
tr("<html>"
|
||||
" <h1>Error [%1]</h1>"
|
||||
" <dl>"
|
||||
" <dt>Command:</dt><dd><code>%3</code></dd>"
|
||||
" <dt>File:</dt><dd>%4</dd>"
|
||||
" <dt>Line:</dt><dd>%5</dd>"
|
||||
" <dt>Error Message:</dt><dd><pre>%2</pre></dd>"
|
||||
" </dl>"
|
||||
"</html>")
|
||||
.arg(demangle(typeid(x).name()))
|
||||
.arg(x.what())
|
||||
.arg(cmd->command())
|
||||
.arg(cmd->file())
|
||||
.arg(cmd->line()));
|
||||
else
|
||||
QMessageBox::critical(this,
|
||||
tr("Test Failed"),
|
||||
tr("<html>"
|
||||
" <h1>Error [%1]</h1>"
|
||||
" <p><code>%2</code></p>"
|
||||
"</html>")
|
||||
.arg(demangle(typeid(x).name()))
|
||||
.arg(QString(x.what()).replace("\n", "<br/>")));
|
||||
}
|
||||
_run->setEnabled(true);
|
||||
_record->setEnabled(true);
|
||||
_record->setChecked(oldRecordState);
|
||||
_progress->hide();
|
||||
}
|
||||
void appendCommand(const QString& txt) {
|
||||
if (!_record->isChecked()) return;
|
||||
_editor->appendPlainText(txt);
|
||||
QScrollBar *vb(_editor->verticalScrollBar());
|
||||
_editor->moveCursor(QTextCursor::End);
|
||||
_editor->ensureCursorVisible();
|
||||
if (!vb) return;
|
||||
vb->setValue(vb->maximum());
|
||||
}
|
||||
void appendCommand(const QString& selector, const QString& txt) {
|
||||
if (!_record->isChecked()) return;
|
||||
QString text(_editor->toPlainText());
|
||||
QStringList lines(text.split("\n"));
|
||||
bool changed(false);
|
||||
while (lines.size() &&
|
||||
(lines.last()=="click "+selector ||
|
||||
lines.last().startsWith("setvalue "+selector+" -> "))) {
|
||||
lines.removeLast();
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
_editor->setPlainText(lines.join("\n"));
|
||||
_editor->moveCursor(QTextCursor::End);
|
||||
_editor->ensureCursorVisible();
|
||||
}
|
||||
appendCommand(txt);
|
||||
}
|
||||
void appendWebLoadFinished(bool ok) {
|
||||
if (!_record->isChecked()) return;
|
||||
QString text(_editor->toPlainText());
|
||||
QStringList lines(text.split("\n"));
|
||||
if (ok && lines.size()>1 &&
|
||||
lines.last().startsWith("expect urlChanged") &&
|
||||
lines.at(lines.size()-2)=="expect loadStarted") {
|
||||
// replace three expect lines by one single line
|
||||
QString url(lines.last().replace("expect urlChanged", "").trimmed());
|
||||
lines.removeLast(); lines.removeLast();
|
||||
_editor->setPlainText(lines.join("\n"));
|
||||
_editor->moveCursor(QTextCursor::End);
|
||||
_editor->ensureCursorVisible();
|
||||
appendCommand("expect load "+url);
|
||||
} else {
|
||||
appendCommand("expect loadFinished "+QString(ok?"true":"false"));
|
||||
}
|
||||
}
|
||||
void unsupportedContent(QNetworkReply* reply) {
|
||||
if (!_record->isChecked()) return;
|
||||
QString filename(reply->url().toString().split('/').last());
|
||||
if (reply->header(QNetworkRequest::ContentDispositionHeader).isValid()) {
|
||||
QString part(reply->header(QNetworkRequest::ContentDispositionHeader)
|
||||
.toString());
|
||||
if (part.contains(QRegularExpression("attachment; *filename="))) {
|
||||
part.replace(QRegularExpression(".*attachment; *filename="), "");
|
||||
if (part.size()) filename = part;
|
||||
}
|
||||
}
|
||||
QString text(_editor->toPlainText());
|
||||
int pos1(text.lastIndexOf(QRegularExpression("^do ")));
|
||||
int pos2(text.lastIndexOf(QRegularExpression("^load ")));
|
||||
int pos3(text.lastIndexOf(QRegularExpression("^click ")));
|
||||
text.insert(std::max({pos1, pos2, pos3}), "download "+filename);
|
||||
_editor->setPlainText(text);
|
||||
_editor->moveCursor(QTextCursor::End);
|
||||
_editor->ensureCursorVisible();
|
||||
}
|
||||
void progress(const QString& txt, int pos, int max) {
|
||||
_progress->setFormat(QString("%1 — %p%").arg(txt));
|
||||
_progress->setMinimum(0);
|
||||
_progress->setMaximum(max);
|
||||
_progress->setValue(pos);
|
||||
}
|
||||
void runEnabled(bool f = true) {
|
||||
_run->setEnabled(false);
|
||||
}
|
||||
void on__run_clicked() {
|
||||
run();
|
||||
}
|
||||
protected:
|
||||
void closeEvent (QCloseEvent*) {
|
||||
void closeEvent(QCloseEvent*) {
|
||||
close(this);
|
||||
}
|
||||
private:
|
||||
enum RunStatus {
|
||||
STATUS_NONE = 0,
|
||||
STATUS_RUNNING,
|
||||
STATUS_SUCCESS,
|
||||
STATUS_ERROR
|
||||
};
|
||||
private:
|
||||
QString _name;
|
||||
};
|
||||
|
@@ -7,16 +7,135 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>628</width>
|
||||
<height>378</height>
|
||||
<height>593</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>DockW&idget</string>
|
||||
<string>Do&ckWidget</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="CodeEditor" name="_editor"/>
|
||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="CodeEditor" name="_editor"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QPushButton" name="_record">
|
||||
<property name="text">
|
||||
<string>Record</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_run">
|
||||
<property name="text">
|
||||
<string>Run</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="_screenshots">
|
||||
<property name="text">
|
||||
<string>Screenshots</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QStackedWidget" name="_status">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_6"/>
|
||||
<widget class="QWidget" name="page_5">
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large">⌛</div></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large; color: green">✔</div></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_4">
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large; color: red">✘</div></string>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="_searchBar" native="true">
|
||||
@@ -72,21 +191,28 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="_pageBar" native="true">
|
||||
<widget class="QWidget" name="_lineBar" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="_page"/>
|
||||
<widget class="QSpinBox" name="_line"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_goPage">
|
||||
<widget class="QPushButton" name="_goLine">
|
||||
<property name="text">
|
||||
<string>page</string>
|
||||
<string>line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="_progress">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
442
src/testgui.hxx
442
src/testgui.hxx
@@ -1,7 +1,7 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
#ifndef TESTGUI_HXX
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <stdexcept>
|
||||
#include <QNetworkReply>
|
||||
#include <QEvent>
|
||||
#include <QTextDocumentFragment>
|
||||
#include <mrw/stdext.hxx>
|
||||
|
||||
class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
@@ -39,7 +38,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
_inEventFilter(false) {
|
||||
setWindowTitle("[*]");
|
||||
setupUi(this);
|
||||
menuViews->addAction(_scriptDock->toggleViewAction());
|
||||
setDockOptions(dockOptions()|QMainWindow::GroupedDragging);
|
||||
menuViews->addAction(_setupScriptDock->toggleViewAction());
|
||||
menuViews->addAction(_scriptCommandsDock->toggleViewAction());
|
||||
menuViews->addAction(_domDock->toggleViewAction());
|
||||
@@ -48,8 +47,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
menuViews->addAction(_logDock->toggleViewAction());
|
||||
menuViews->addAction(_sourceDock->toggleViewAction());
|
||||
menuViews->addAction(_executeDock->toggleViewAction());
|
||||
_progress->hide();
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
|
||||
QSettings settings("mrw", "webtester");
|
||||
restoreGeometry(settings.value("geometry").toByteArray());
|
||||
restoreState(settings.value("windowstate").toByteArray());
|
||||
@@ -64,22 +62,22 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
_web->installEventFilter(this); // track mouse and keyboard
|
||||
pg->setForwardUnsupportedContent(true);
|
||||
_commands->setText(Script().commands(Script::HTML));
|
||||
assert(connect(menuFile, SIGNAL(aboutToShow()), SLOT(fileMenuOpened())));
|
||||
assert(connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
|
||||
SLOT(focusChanged(QWidget*, QWidget*))));
|
||||
assert(connect(pg, SIGNAL(uploadFile(QString)), SLOT(uploadFile(QString))));
|
||||
assert(connect(pg, SIGNAL(unsupportedContent(QNetworkReply*)),
|
||||
SLOT(unsupportedContent(QNetworkReply*))));
|
||||
assert(connect(pg, SIGNAL(downloadRequested(const QNetworkRequest&)),
|
||||
SLOT(downloadRequested(const QNetworkRequest&))));
|
||||
//assert(connect(_testscript, SIGNAL(include(QString)), SLOT(include(QString))));
|
||||
assert(connect(_testscript, SIGNAL(link(QString)), SLOT(include(QString))));
|
||||
if (setupScript.size()) loadSetup(setupScript);
|
||||
if (scriptFile.size()) loadFile(scriptFile);
|
||||
if (scriptFile.size()) load(scriptFile);
|
||||
}
|
||||
virtual ~TestGUI() {}
|
||||
public Q_SLOTS:
|
||||
void on__load_clicked() {
|
||||
enterText(true);
|
||||
if (_record->isChecked())
|
||||
appendCommand("load "+map(_url->currentText()));
|
||||
appendCommand("load "+map(_url->currentText()));
|
||||
storeUrl(_url->currentText());
|
||||
_webprogress->setFormat(_url->currentText());
|
||||
_web->load(_url->currentText());
|
||||
@@ -91,123 +89,34 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
void on__actionOpen_triggered() {
|
||||
QString name(QFileDialog::getOpenFileName(this, tr("Open Test Script")));
|
||||
if (name.isEmpty()) return;
|
||||
loadFile(name);
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
load(name);
|
||||
}
|
||||
void on__actionOpenSetupScript_triggered() {
|
||||
QString name(QFileDialog::getOpenFileName(this, tr("Open Setup Script")));
|
||||
if (name.isEmpty()) return;
|
||||
loadSetup(name);
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
}
|
||||
void on__actionRevertToSaved_triggered() {
|
||||
loadFile(_filename);
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
ScriptFile* active(activeScriptFile());
|
||||
if (active) active->load();
|
||||
}
|
||||
void on__actionSaveAs_triggered() {
|
||||
ScriptFile* active(activeScriptFile());
|
||||
if (!active) return;
|
||||
QString name(QFileDialog::getSaveFileName(this, tr("Save Test Script")));
|
||||
if (name.isEmpty()) return;
|
||||
_filename = name;
|
||||
on__actionSave_triggered();
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
if (!name.isEmpty()) active->save(name);
|
||||
}
|
||||
void on__actionSave_triggered() {
|
||||
QFile file(_filename);
|
||||
try {
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
throw std::runtime_error("file open failed");
|
||||
QTextStream out(&file);
|
||||
out<<_testscript->toPlainText();
|
||||
if (out.status()!=QTextStream::Ok)
|
||||
throw std::runtime_error(std::string("file write failed (")
|
||||
+char(out.status()+48)+")");
|
||||
_actionSave->setEnabled(true);
|
||||
_actionRevertToSaved->setEnabled(true);
|
||||
setWindowModified(false);
|
||||
setWindowTitle(_filename+"[*]");
|
||||
} catch(const std::exception& x) {
|
||||
QMessageBox::critical(this, tr("Save Failed"),
|
||||
tr("Saving test script failed, %2. "
|
||||
"Cannot write test script to file %1.")
|
||||
.arg(_filename).arg(x.what()));
|
||||
}
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
ScriptFile* active(activeScriptFile());
|
||||
if (active) active->save();
|
||||
}
|
||||
void on__actionClear_triggered() {
|
||||
if (isWindowModified() &&
|
||||
QMessageBox::question(this, tr("Changes Not Saved"),
|
||||
tr("Clear script without saving changes?"))
|
||||
!= QMessageBox::Yes)
|
||||
return;
|
||||
_testscript->clear();
|
||||
_log->clear();
|
||||
_filename.clear();
|
||||
_actionSave->setEnabled(false);
|
||||
_actionRevertToSaved->setEnabled(false);
|
||||
setWindowTitle("[*]");
|
||||
setWindowModified(false);
|
||||
_status->setCurrentIndex(STATUS_NONE);
|
||||
ScriptFile* active(activeScriptFile());
|
||||
if (active) active->clear();
|
||||
}
|
||||
void on__run_clicked() {
|
||||
_progress->reset();
|
||||
_progress->show();
|
||||
_status->setCurrentIndex(STATUS_RUNNING);
|
||||
bool oldRecordState(_record->isChecked());
|
||||
_record->setChecked(false);
|
||||
_record->setEnabled(false);
|
||||
_run->setEnabled(false);
|
||||
Script script;
|
||||
try {
|
||||
connect(&script, SIGNAL(logging(QString)), SLOT(logging(QString)));
|
||||
connect(&script, SIGNAL(progress(QString, int, int)), SLOT(progress(QString, int, int)));
|
||||
std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite"));
|
||||
if (_setupscriptactive->isEnabled()
|
||||
&& _setupscriptactive->isChecked()) {
|
||||
script.parse(_setupscript->toPlainText().split('\n'), "setup");
|
||||
script.run(_web->page()->mainFrame(), testsuites, QString(),
|
||||
_screenshots->isChecked());
|
||||
script.reset();
|
||||
}
|
||||
QString text(_testscript->textCursor().selection().toPlainText());
|
||||
if (text.isEmpty()) text = _testscript->toPlainText();
|
||||
script.parse(text.split('\n'), "script");
|
||||
script.run(_web->page()->mainFrame(), testsuites, QString(),
|
||||
_screenshots->isChecked());
|
||||
_status->setCurrentIndex(STATUS_SUCCESS);
|
||||
} catch (std::exception &x) {
|
||||
_status->setCurrentIndex(STATUS_ERROR);
|
||||
std::shared_ptr<Command> cmd(script.command());
|
||||
if (cmd)
|
||||
QMessageBox::critical(this,
|
||||
tr("Test Failed"),
|
||||
tr("<html>"
|
||||
" <h1>Error [%1]</h1>"
|
||||
" <dl>"
|
||||
" <dt>Command:</dt><dd><code>%3</code></dd>"
|
||||
" <dt>File:</dt><dd>%4</dd>"
|
||||
" <dt>Line:</dt><dd>%5</dd>"
|
||||
" <dt>Error Message:</dt><dd><pre>%2</pre></dd>"
|
||||
" </dl>"
|
||||
"</html>")
|
||||
.arg(demangle(typeid(x).name()))
|
||||
.arg(x.what())
|
||||
.arg(cmd->command())
|
||||
.arg(cmd->file())
|
||||
.arg(cmd->line()));
|
||||
else
|
||||
QMessageBox::critical(this,
|
||||
tr("Test Failed"),
|
||||
tr("<html>"
|
||||
" <h1>Error [%1]</h1>"
|
||||
" <p><code>%2</code></p>"
|
||||
"</html>")
|
||||
.arg(demangle(typeid(x).name()))
|
||||
.arg(QString(x.what()).replace("\n", "<br/>")));
|
||||
}
|
||||
_run->setEnabled(true);
|
||||
_record->setEnabled(true);
|
||||
_record->setChecked(oldRecordState);
|
||||
_progress->hide();
|
||||
void on__actionRun_triggered() {
|
||||
ScriptFile* active(activeScriptFile());
|
||||
if (active) active->run();
|
||||
}
|
||||
void on__focused_clicked() {
|
||||
enterText(true);
|
||||
@@ -228,8 +137,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
}
|
||||
void on__web_linkClicked(const QUrl& url) {
|
||||
enterText(true);
|
||||
if (_record->isChecked())
|
||||
appendCommand("load "+map(url.url()));
|
||||
appendCommand("load "+map(url.url()));
|
||||
}
|
||||
void on__web_loadProgress(int progress) {
|
||||
enterText(true);
|
||||
@@ -237,8 +145,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
}
|
||||
void on__web_loadStarted() {
|
||||
enterText(true);
|
||||
if (_record->isChecked())
|
||||
appendCommand("expect "+map("loadStarted"));
|
||||
appendCommand("expect "+map("loadStarted"));
|
||||
_webprogress->setValue(0);
|
||||
_urlStack->setCurrentIndex(PROGRESS_VIEW);
|
||||
}
|
||||
@@ -252,8 +159,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
_webprogress->setFormat(url.url());
|
||||
storeUrl(url);
|
||||
enterText(true);
|
||||
if (_record->isChecked())
|
||||
appendCommand("expect "+map("urlChanged "+url.url()));
|
||||
appendCommand("expect "+map("urlChanged "+url.url()));
|
||||
}
|
||||
void on__web_selectionChanged() {
|
||||
_source->setPlainText(_web->hasSelection()
|
||||
@@ -262,24 +168,8 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
}
|
||||
void on__web_loadFinished(bool ok) {
|
||||
enterText(true);
|
||||
if (_record->isChecked()) {
|
||||
QString text(_testscript->toPlainText());
|
||||
QStringList lines(text.split("\n"));
|
||||
if (ok && lines.size()>1 &&
|
||||
lines.last().startsWith("expect urlChanged") &&
|
||||
lines.at(lines.size()-2)=="expect loadStarted") {
|
||||
// replace three expect lines by one single line
|
||||
QString url(lines.last().replace("expect urlChanged", "").trimmed());
|
||||
lines.removeLast(); lines.removeLast();
|
||||
_testscript->setPlainText(lines.join("\n"));
|
||||
_testscript->moveCursor(QTextCursor::End);
|
||||
_testscript->ensureCursorVisible();
|
||||
appendCommand("expect "+map("load "+url));
|
||||
} else {
|
||||
appendCommand("expect "+map("loadFinished "
|
||||
+QString(ok?"true":"false")));
|
||||
}
|
||||
}
|
||||
for (auto testscript: _testscripts)
|
||||
testscript->appendWebLoadFinished(ok);
|
||||
_urlStack->setCurrentIndex(URL_VIEW);
|
||||
on__web_selectionChanged();
|
||||
setLinks();
|
||||
@@ -287,8 +177,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
setDom();
|
||||
}
|
||||
void on__setupscript_textChanged() {
|
||||
bool oldRecordState(_record->isChecked());
|
||||
_run->setEnabled(false);
|
||||
for (auto testscript: _testscripts) testscript->runEnabled(false);
|
||||
_setupscriptactive->setEnabled(false);
|
||||
try {
|
||||
_setupscriptstatus->setText(trUtf8("?"));
|
||||
@@ -305,8 +194,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
} catch (std::exception &x) {
|
||||
_setupscriptstatus->setText(trUtf8("✘"));
|
||||
}
|
||||
_run->setEnabled(true);
|
||||
_record->setChecked(oldRecordState);
|
||||
for (auto testscript: _testscripts) testscript->runEnabled(true);
|
||||
}
|
||||
void on__forms_currentItemChanged(QTreeWidgetItem* item, QTreeWidgetItem*) {
|
||||
if (!item) return;
|
||||
@@ -318,32 +206,13 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
}
|
||||
void uploadFile(QString filename) {
|
||||
enterText(true);
|
||||
if (_record->isChecked())
|
||||
appendCommand("upload "+map(filename));
|
||||
appendCommand("upload "+map(filename));
|
||||
}
|
||||
void unsupportedContent(QNetworkReply* reply) {
|
||||
if (!_record->isChecked()) return;
|
||||
QString filename(reply->url().toString().split('/').last());
|
||||
if (reply->header(QNetworkRequest::ContentDispositionHeader).isValid()) {
|
||||
QString part(reply->header(QNetworkRequest::ContentDispositionHeader)
|
||||
.toString());
|
||||
if (part.contains(QRegularExpression("attachment; *filename="))) {
|
||||
part.replace(QRegularExpression(".*attachment; *filename="), "");
|
||||
if (part.size()) filename = part;
|
||||
}
|
||||
}
|
||||
QString text(_testscript->toPlainText());
|
||||
int pos1(text.lastIndexOf(QRegularExpression("^do ")));
|
||||
int pos2(text.lastIndexOf(QRegularExpression("^load ")));
|
||||
int pos3(text.lastIndexOf(QRegularExpression("^click ")));
|
||||
text.insert(std::max({pos1, pos2, pos3}), "download "+filename);
|
||||
_testscript->setPlainText(text);
|
||||
_testscript->moveCursor(QTextCursor::End);
|
||||
_testscript->ensureCursorVisible();
|
||||
for (auto testscript: _testscripts) testscript->unsupportedContent(reply);
|
||||
}
|
||||
void downloadRequested(const QNetworkRequest&) {
|
||||
if (_record->isChecked())
|
||||
appendCommand("download2");
|
||||
appendCommand("download2");
|
||||
}
|
||||
void logging(const QString& txt) {
|
||||
_log->appendPlainText(txt);
|
||||
@@ -351,49 +220,80 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
if (!vb) return;
|
||||
vb->setValue(vb->maximum());
|
||||
}
|
||||
void progress(const QString& txt, int pos, int max) {
|
||||
_progress->setFormat(QString("%1 — %p%").arg(txt));
|
||||
_progress->setMinimum(0);
|
||||
_progress->setMaximum(max);
|
||||
_progress->setValue(pos);
|
||||
void fileMenuOpened() {
|
||||
focusChanged(nullptr, nullptr);
|
||||
}
|
||||
void appendCommand(const QString& txt) {
|
||||
_testscript->appendPlainText(txt);
|
||||
QScrollBar *vb(_testscript->verticalScrollBar());
|
||||
_testscript->moveCursor(QTextCursor::End);
|
||||
_testscript->ensureCursorVisible();
|
||||
if (!vb) return;
|
||||
vb->setValue(vb->maximum());
|
||||
void modified(ScriptFile* win) {
|
||||
focusChanged(nullptr, win);
|
||||
}
|
||||
void include(QString name) {
|
||||
if (_testscripts.contains(name)) return;
|
||||
void focusChanged(QWidget*, QWidget* focus) {
|
||||
ScriptFile* active(activeScriptFile(focus));
|
||||
if (active)
|
||||
setWindowFilePath(active->name());
|
||||
else
|
||||
setWindowFilePath(QString());
|
||||
_actionRevertToSaved->setEnabled(active);
|
||||
_actionSaveAs->setEnabled(active);
|
||||
_actionSave->setEnabled(active&&active->isWindowModified());
|
||||
_actionClear->setEnabled(active);
|
||||
_actionRun->setEnabled(active);
|
||||
}
|
||||
void activate(QString name) {
|
||||
QFileInfo info(name);
|
||||
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
||||
if (!_testscripts.contains(name)) return load(name);
|
||||
_testscripts[name]->show();
|
||||
_testscripts[name]->raise();
|
||||
_testscripts[name]->activateWindow();
|
||||
}
|
||||
void load(QString name) {
|
||||
QFileInfo info(name);
|
||||
if (info.absoluteDir()==QDir::current()) name = info.fileName();
|
||||
if (_testscripts.contains(name)) try {
|
||||
_testscripts[name]->load(name);
|
||||
return activate(name);
|
||||
} catch(const std::exception& x) {
|
||||
remove(_testscripts[name]);
|
||||
}
|
||||
QDockWidget* first(_testscripts.isEmpty()?_setupScriptDock:_testscripts.last());
|
||||
_testscripts[name] = new ScriptFile(this);
|
||||
// assert(connect(_testscripts[name], SIGNAL(include(QString)), SLOT(include(QString))));
|
||||
assert(connect(_testscripts[name], SIGNAL(link(QString)), SLOT(include(QString))));
|
||||
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(close(ScriptFile*)), SLOT(remove(ScriptFile*))));
|
||||
QFile file(name);
|
||||
assert(connect(_testscripts[name], SIGNAL(run(const QString&, const QString&, bool, Script&)), SLOT(run(const QString&, const QString&, bool, Script&))));
|
||||
try {
|
||||
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
|
||||
throw std::runtime_error("file open failed");
|
||||
_testscripts[name]->editor()->setPlainText(QString::fromUtf8(file.readAll()));
|
||||
if (file.error()!=QFileDevice::NoError)
|
||||
throw std::runtime_error("file read failed");
|
||||
_testscripts[name]->name(name);
|
||||
tabifyDockWidget(_scriptDock, _testscripts[name]);
|
||||
// QDockWidget* d(0);
|
||||
// for (QWidget* w(QApplication::focusWidget()); w&&!(d=qobject_cast<QDockWidget*>(w));
|
||||
// w=qobject_cast<QWidget*>(w->parent()));
|
||||
// if (d) d->raise();
|
||||
_testscripts[name]->raise();
|
||||
_testscripts[name]->load(name);
|
||||
tabifyDockWidget(first, _testscripts[name]);
|
||||
activate(name);
|
||||
} catch(const std::exception& x) {
|
||||
remove(_testscripts[name]);
|
||||
}
|
||||
}
|
||||
void remove(ScriptFile* scriptfile) {
|
||||
/// @todo check if modified
|
||||
_testscripts.remove(scriptfile->name());
|
||||
delete scriptfile;
|
||||
}
|
||||
void run(const QString& name, const QString& text, bool screenshots, Script& script) {
|
||||
std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite"));
|
||||
assert(connect(&script, SIGNAL(logging(QString)), SLOT(logging(QString))));
|
||||
if (_setupscriptactive->isEnabled()
|
||||
&& _setupscriptactive->isChecked()) {
|
||||
script.parse(_setupscript->toPlainText().split('\n'), "setup");
|
||||
script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots);
|
||||
script.reset();
|
||||
}
|
||||
script.parse(text.split('\n'), name);
|
||||
script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots);
|
||||
}
|
||||
protected:
|
||||
ScriptFile* activeScriptFile(QWidget* focus=nullptr) {
|
||||
//for (auto win: _testscripts) if (win->isActiveWindow()) return win;
|
||||
ScriptFile* active(nullptr);
|
||||
for (QObject* wid(focus?focus:QApplication::focusWidget()); !active && wid; wid = wid->parent())
|
||||
active = dynamic_cast<ScriptFile*>(wid);
|
||||
return active;
|
||||
}
|
||||
void closeEvent(QCloseEvent* event) {
|
||||
QSettings settings("mrw", "webtester");
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
@@ -440,41 +340,39 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
case QEvent::MouseButtonRelease: {
|
||||
enterText(true);
|
||||
_lastFocused=element;
|
||||
if (_record->isChecked()) {
|
||||
if (!element.isNull()) {
|
||||
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 ...
|
||||
QStringList v;
|
||||
for (QWebElement option: _lastFocused.findAll("option")) {
|
||||
//! @bug QT does not support selected
|
||||
if (option.evaluateJavaScript("this.selected").toBool())
|
||||
v += value(option);
|
||||
}
|
||||
setValue(selected, v);
|
||||
} 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 {
|
||||
if (_web->page()->selectedText() != "") {
|
||||
// user has selected a text, append a check
|
||||
appendCommand("exists "+map(selected)
|
||||
+" -> "+_web->page()->selectedText());
|
||||
_web->page()->findText(QString());
|
||||
} else {
|
||||
// user has clicked without selection, append a click
|
||||
appendCommand("click "+map(selected));
|
||||
}
|
||||
if (!element.isNull()) {
|
||||
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 ...
|
||||
QStringList v;
|
||||
for (QWebElement option: _lastFocused.findAll("option")) {
|
||||
//! @bug QT does not support selected
|
||||
if (option.evaluateJavaScript("this.selected").toBool())
|
||||
v += value(option);
|
||||
}
|
||||
setValue(selected, v);
|
||||
} 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, but where?");
|
||||
if (_web->page()->selectedText() != "") {
|
||||
// user has selected a text, append a check
|
||||
appendCommand("exists "+map(selected)
|
||||
+" -> "+_web->page()->selectedText());
|
||||
_web->page()->findText(QString());
|
||||
} else {
|
||||
// user has clicked without selection, append a click
|
||||
appendCommand("click "+map(selected));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appendCommand("# click, but where?");
|
||||
}
|
||||
} break;
|
||||
case QEvent::MouseButtonPress: {
|
||||
@@ -505,26 +403,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
_url->setCurrentText(u.url());
|
||||
}
|
||||
}
|
||||
void loadFile(QString name) {
|
||||
QFile file(name);
|
||||
try {
|
||||
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
|
||||
throw std::runtime_error("file open failed");
|
||||
_testscript->setPlainText(QString::fromUtf8(file.readAll()));
|
||||
if (file.error()!=QFileDevice::NoError)
|
||||
throw std::runtime_error("file read failed");
|
||||
_filename = name;
|
||||
_actionSave->setEnabled(true);
|
||||
_actionRevertToSaved->setEnabled(true);
|
||||
setWindowTitle(name+"[*]");
|
||||
setWindowModified(false);
|
||||
} catch(const std::exception& x) {
|
||||
QMessageBox::critical(this, tr("Open Failed"),
|
||||
tr("Reading test script failed, %2. "
|
||||
"Cannot read test script from file %1.")
|
||||
.arg(name).arg(x.what()));
|
||||
}
|
||||
}
|
||||
void loadSetup(QString name) {
|
||||
QFile file(name);
|
||||
try {
|
||||
@@ -535,10 +413,10 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
throw std::runtime_error("file read failed");
|
||||
on__setupscript_textChanged();
|
||||
} catch(const std::exception& x) {
|
||||
QMessageBox::critical(this, tr("Open Failed"),
|
||||
tr("Reading test script failed, %2. "
|
||||
"Cannot read test script from file %1.")
|
||||
.arg(name).arg(x.what()));
|
||||
QMessageBox::critical(this, tr("Open Failed"),
|
||||
tr("Reading test script failed, %2. "
|
||||
"Cannot read test script from file %1.")
|
||||
.arg(name).arg(x.what()));
|
||||
}
|
||||
}
|
||||
void enterText(bool force=false) {
|
||||
@@ -561,9 +439,9 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
return QString(); // error
|
||||
}
|
||||
void highlight(QWebElement element) {
|
||||
element
|
||||
.evaluateJavaScript("var selection = window.getSelection();"
|
||||
"selection.setBaseAndExtent(this, 0, this, 1);");
|
||||
element
|
||||
.evaluateJavaScript("var selection = window.getSelection();"
|
||||
"selection.setBaseAndExtent(this, 0, this, 1);");
|
||||
}
|
||||
QWebElement focused(QMouseEvent* event = 0) {
|
||||
for (QWebElement element: _web->page()->currentFrame()->findAllElements("*")) {
|
||||
@@ -644,41 +522,26 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
return in;
|
||||
}
|
||||
void javascript(const QString& selector, QString code) {
|
||||
if (_record->isChecked())
|
||||
appendCommand("do "+map(selector)+"\n "
|
||||
+map(code).replace("\n", "\n "));
|
||||
}
|
||||
void cleanup(const QString& selector) {
|
||||
QString text(_testscript->toPlainText());
|
||||
QStringList lines(text.split("\n"));
|
||||
bool changed(false);
|
||||
while (lines.size() &&
|
||||
(lines.last()=="click "+selector ||
|
||||
lines.last().startsWith("setvalue "+selector+" -> "))) {
|
||||
lines.removeLast();
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
_testscript->setPlainText(lines.join("\n"));
|
||||
_testscript->moveCursor(QTextCursor::End);
|
||||
_testscript->ensureCursorVisible();
|
||||
}
|
||||
appendCommand("do "+map(selector)+"\n "
|
||||
+map(code).replace("\n", "\n "));
|
||||
}
|
||||
void setValue(const QString& selector, QString code) {
|
||||
if (_record->isChecked()) {
|
||||
cleanup(selector);
|
||||
appendCommand("setvalue "+map(selector)+" -> '"
|
||||
+map(code).replace("'", "\\'").replace("\n", "\\n")+"'");
|
||||
}
|
||||
appendCommand(selector,
|
||||
"setvalue "+map(selector)+" -> '"
|
||||
+map(code).replace("'", "\\'").replace("\n", "\\n")+"'");
|
||||
}
|
||||
void setValue(const QString& selector, QStringList code) {
|
||||
if (_record->isChecked()) {
|
||||
cleanup(selector);
|
||||
appendCommand("setvalue "+map(selector)+" -> '"+
|
||||
map(code.replaceInStrings("'", "\\'")
|
||||
.replaceInStrings("\n", "\\n")
|
||||
.join("', '")+"'"));
|
||||
}
|
||||
appendCommand(selector,
|
||||
"setvalue "+map(selector)+" -> '"+
|
||||
map(code.replaceInStrings("'", "\\'")
|
||||
.replaceInStrings("\n", "\\n")
|
||||
.join("', '")+"'"));
|
||||
}
|
||||
void appendCommand(const QString& txt) {
|
||||
for (auto testscript: _testscripts) testscript->appendCommand(txt);
|
||||
}
|
||||
void appendCommand(const QString& selector, const QString& txt) {
|
||||
for (auto testscript: _testscripts) testscript->appendCommand(selector, txt);
|
||||
}
|
||||
bool handleMooTools(QWebElement element) {
|
||||
QString selected(selector(element));
|
||||
@@ -697,10 +560,9 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
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("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") {
|
||||
@@ -861,7 +723,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
case QEvent::LayoutDirectionChange: return "QEvent::LayoutDirectionChange - The direction of layouts changed.";
|
||||
case QEvent::LayoutRequest: return "QEvent::LayoutRequest - Widget layout needs to be redone.";
|
||||
case QEvent::Leave: return "QEvent::Leave - Mouse leaves widget's boundaries.";
|
||||
//case QEvent::LeaveEditFocus: return "QEvent::LeaveEditFocus - An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined.";
|
||||
//case QEvent::LeaveEditFocus: return "QEvent::LeaveEditFocus - An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined.";
|
||||
case QEvent::LeaveWhatsThisMode: return "QEvent::LeaveWhatsThisMode - Send to toplevel widgets when the application leaves \"What's This?\" mode.";
|
||||
case QEvent::LocaleChange: return "QEvent::LocaleChange - The system locale has changed.";
|
||||
case QEvent::NonClientAreaMouseButtonDblClick: return "QEvent::NonClientAreaMouseButtonDblClick - A mouse double click occurred outside the client area.";
|
||||
@@ -887,7 +749,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
case QEvent::Polish: return "QEvent::Polish - The widget is polished.";
|
||||
case QEvent::PolishRequest: return "QEvent::PolishRequest - The widget should be polished.";
|
||||
case QEvent::QueryWhatsThis: return "QEvent::QueryWhatsThis - The widget should accept the event if it has \"What's This?\" help.";
|
||||
//case QEvent::ReadOnlyChange: return "QEvent::ReadOnlyChange - Widget's read-only state has changed (since Qt 5.4).";
|
||||
//case QEvent::ReadOnlyChange: return "QEvent::ReadOnlyChange - Widget's read-only state has changed (since Qt 5.4).";
|
||||
case QEvent::RequestSoftwareInputPanel: return "QEvent::RequestSoftwareInputPanel - A widget wants to open a software input panel (SIP).";
|
||||
case QEvent::Resize: return "QEvent::Resize - Widget's size changed (QResizeEvent).";
|
||||
case QEvent::ScrollPrepare: return "QEvent::ScrollPrepare - The object needs to fill in its geometry information (QScrollPrepareEvent).";
|
||||
@@ -942,12 +804,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
|
||||
URL_VIEW = 0,
|
||||
PROGRESS_VIEW
|
||||
};
|
||||
enum RunStatus {
|
||||
STATUS_NONE = 0,
|
||||
STATUS_RUNNING,
|
||||
STATUS_SUCCESS,
|
||||
STATUS_ERROR
|
||||
};
|
||||
private:
|
||||
QString _filename;
|
||||
QWebElement _lastFocused; // cache for last focussed element
|
||||
|
225
src/testgui.ui
225
src/testgui.ui
@@ -10,6 +10,9 @@
|
||||
<height>1180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
@@ -101,7 +104,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>888</width>
|
||||
<height>30</height>
|
||||
<height>34</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuViews">
|
||||
@@ -115,14 +118,13 @@
|
||||
</property>
|
||||
<addaction name="_actionOpen"/>
|
||||
<addaction name="_actionOpenSetupScript"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionSave"/>
|
||||
<addaction name="_actionSaveAs"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionRun"/>
|
||||
<addaction name="_actionRunLine"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionRevertToSaved"/>
|
||||
<addaction name="_actionClear"/>
|
||||
<addaction name="_actionRun"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="_actionQuit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
@@ -138,7 +140,7 @@
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QDockWidget" name="_domDock">
|
||||
<property name="windowTitle">
|
||||
<string>D&OM Tree</string>
|
||||
<string>DOM &Tree</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
@@ -393,144 +395,6 @@ this.dispatchEvent(evObj);</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="_scriptDock">
|
||||
<property name="windowTitle">
|
||||
<string>&Test Script</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>4</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_12">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="CodeEditor" name="_testscript"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QPushButton" name="_record">
|
||||
<property name="text">
|
||||
<string>Record</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="_run">
|
||||
<property name="text">
|
||||
<string>Run</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="_screenshots">
|
||||
<property name="text">
|
||||
<string>Screenshots</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QStackedWidget" name="_status">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_6"/>
|
||||
<widget class="QWidget" name="page_5">
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large">⌛</div></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large; color: green">✔</div></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_4">
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><div style="font-size: xx-large; color: red">✘</div></string>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="_progress">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="_logDock">
|
||||
<property name="windowTitle">
|
||||
<string>Scri&pt Run Log</string>
|
||||
@@ -699,6 +563,9 @@ this.dispatchEvent(evObj);</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionSaveAs">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save &As ...</string>
|
||||
</property>
|
||||
@@ -715,6 +582,9 @@ this.dispatchEvent(evObj);</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionRun">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Run</string>
|
||||
</property>
|
||||
@@ -728,6 +598,9 @@ this.dispatchEvent(evObj);</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="_actionClear">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Clear</string>
|
||||
</property>
|
||||
@@ -986,38 +859,6 @@ this.dispatchEvent(evObj);</string>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_actionTestScript</sender>
|
||||
<signal>triggered(bool)</signal>
|
||||
<receiver>_scriptDock</receiver>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>443</x>
|
||||
<y>155</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_scriptDock</sender>
|
||||
<signal>visibilityChanged(bool)</signal>
|
||||
<receiver>_actionTestScript</receiver>
|
||||
<slot>setChecked(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>155</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_actionLog</sender>
|
||||
<signal>triggered(bool)</signal>
|
||||
@@ -1066,22 +907,6 @@ this.dispatchEvent(evObj);</string>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_actionRun</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>_run</receiver>
|
||||
<slot>click()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>299</x>
|
||||
<y>90</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_url</sender>
|
||||
<signal>activated(int)</signal>
|
||||
@@ -1098,21 +923,5 @@ this.dispatchEvent(evObj);</string>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>_testscript</sender>
|
||||
<signal>modificationChanged(bool)</signal>
|
||||
<receiver>TestGUI</receiver>
|
||||
<slot>setWindowModified(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>126</x>
|
||||
<y>144</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>443</x>
|
||||
<y>589</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
@@ -4,22 +4,22 @@
|
||||
#include <version.hxx>
|
||||
|
||||
int main(int argc, char *argv[]) try {
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationDisplayName(a.tr("WebTester"));
|
||||
a.setApplicationName(webtester::package_name().c_str());
|
||||
a.setApplicationVersion(webtester::version().c_str());
|
||||
QApplication app(argc, argv);
|
||||
app.setApplicationDisplayName(app.tr("WebTester"));
|
||||
app.setApplicationName(webtester::package_name().c_str());
|
||||
app.setApplicationVersion(webtester::version().c_str());
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addOption(QCommandLineOption
|
||||
(QStringList()<<"u"<<"url",
|
||||
"set initial URL to <url>", "url"));
|
||||
parser.process(a);
|
||||
parser.process(app);
|
||||
QStringList scripts(parser.positionalArguments());
|
||||
TestGUI w(0, parser.value("url"),
|
||||
scripts.size()>1?scripts[0]:"",
|
||||
scripts.size()>1?scripts[1]:scripts.size()?scripts[0]:"");
|
||||
w.show();
|
||||
return a.exec();
|
||||
TestGUI win(0, parser.value("url"),
|
||||
scripts.size()>1?scripts[0]:"",
|
||||
scripts.size()>1?scripts[1]:scripts.size()?scripts[0]:"");
|
||||
win.show();
|
||||
return app.exec();
|
||||
} catch (std::exception &x) {
|
||||
std::cerr<<"**** error: "<<x.what()<<std::endl;
|
||||
return 1;
|
||||
|
Reference in New Issue
Block a user