feat(Storybook): Add tests runner available from the app
This commit is contained in:
parent
0caec2ab1c
commit
8a996a9175
|
@ -52,6 +52,7 @@ add_library(${PROJECT_LIB}
|
||||||
modelutils.cpp modelutils.h
|
modelutils.cpp modelutils.h
|
||||||
pagesmodel.h pagesmodel.cpp
|
pagesmodel.h pagesmodel.cpp
|
||||||
sectionsdecoratormodel.cpp sectionsdecoratormodel.h
|
sectionsdecoratormodel.cpp sectionsdecoratormodel.h
|
||||||
|
testsrunner.h testsrunner.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
|
@ -105,6 +106,9 @@ add_executable(QmlTests
|
||||||
qmlTests/main.cpp
|
qmlTests/main.cpp
|
||||||
qmlTests/src/TextUtils.cpp qmlTests/src/TextUtils.h
|
qmlTests/src/TextUtils.cpp qmlTests/src/TextUtils.h
|
||||||
${TEST_QML_FILES})
|
${TEST_QML_FILES})
|
||||||
|
|
||||||
|
add_dependencies(QmlTests StatusQ)
|
||||||
|
|
||||||
target_compile_definitions(QmlTests PRIVATE
|
target_compile_definitions(QmlTests PRIVATE
|
||||||
QML_IMPORT_ROOT="${CMAKE_CURRENT_LIST_DIR}"
|
QML_IMPORT_ROOT="${CMAKE_CURRENT_LIST_DIR}"
|
||||||
STATUSQ_MODULE_IMPORT_PATH="${STATUSQ_MODULE_IMPORT_PATH}"
|
STATUSQ_MODULE_IMPORT_PATH="${STATUSQ_MODULE_IMPORT_PATH}"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "figmalinks.h"
|
#include "figmalinks.h"
|
||||||
#include "pagesmodel.h"
|
#include "pagesmodel.h"
|
||||||
#include "sectionsdecoratormodel.h"
|
#include "sectionsdecoratormodel.h"
|
||||||
|
#include "testsrunner.h"
|
||||||
|
|
||||||
struct PagesModelInitialized : public PagesModel {
|
struct PagesModelInitialized : public PagesModel {
|
||||||
explicit PagesModelInitialized(QObject *parent = nullptr)
|
explicit PagesModelInitialized(QObject *parent = nullptr)
|
||||||
|
@ -64,6 +65,16 @@ int main(int argc, char *argv[])
|
||||||
qmlRegisterSingletonType<CacheCleaner>(
|
qmlRegisterSingletonType<CacheCleaner>(
|
||||||
"Storybook", 1, 0, "CacheCleaner", cleanerFactory);
|
"Storybook", 1, 0, "CacheCleaner", cleanerFactory);
|
||||||
|
|
||||||
|
auto runnerFactory = [](QQmlEngine* engine, QJSEngine*) {
|
||||||
|
return new TestsRunner(
|
||||||
|
QCoreApplication::applicationDirPath() + QStringLiteral("/QmlTests"),
|
||||||
|
QML_IMPORT_ROOT + QStringLiteral("/qmlTests/tests"));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
qmlRegisterSingletonType<TestsRunner>(
|
||||||
|
"Storybook", 1, 0, "TestsRunner", runnerFactory);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
const QUrl url(QUrl::fromLocalFile(QML_IMPORT_ROOT + QStringLiteral("/main.qml")));
|
const QUrl url(QUrl::fromLocalFile(QML_IMPORT_ROOT + QStringLiteral("/main.qml")));
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
Item {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
TestRunnerControls {
|
||||||
|
mode: radioButtonsGroup.checkedButton.mode
|
||||||
|
|
||||||
|
numberOfFailedTests: 42
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
onRunClicked: logs.logEvent("Run clicked")
|
||||||
|
onAbortClicked: logs.logEvent("Abort clicked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 200
|
||||||
|
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
|
||||||
|
ButtonGroup {
|
||||||
|
id: radioButtonsGroup
|
||||||
|
|
||||||
|
buttons: radioButtonsRow.children
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: radioButtonsRow
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.Base
|
||||||
|
|
||||||
|
text: "Base"
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.InProgress
|
||||||
|
|
||||||
|
text: "In progress"
|
||||||
|
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.Failed
|
||||||
|
|
||||||
|
text: "Failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.Success
|
||||||
|
|
||||||
|
text: "Success"
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.Aborted
|
||||||
|
|
||||||
|
text: "Aborted"
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
readonly property int mode: TestRunnerControls.Mode.Crashed
|
||||||
|
|
||||||
|
text: "Crashed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// category: Controls
|
|
@ -14,7 +14,7 @@ public slots:
|
||||||
QML_IMPORT_ROOT + QStringLiteral("/../ui/app"),
|
QML_IMPORT_ROOT + QStringLiteral("/../ui/app"),
|
||||||
QML_IMPORT_ROOT + QStringLiteral("/../ui/imports"),
|
QML_IMPORT_ROOT + QStringLiteral("/../ui/imports"),
|
||||||
QML_IMPORT_ROOT + QStringLiteral("/stubs"),
|
QML_IMPORT_ROOT + QStringLiteral("/stubs"),
|
||||||
QML_IMPORT_ROOT + QStringLiteral("/mocks"),
|
QML_IMPORT_ROOT + QStringLiteral("/src")
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& path : additionalImportPaths)
|
for (const auto& path : additionalImportPaths)
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtTest 1.15
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
|
TestCase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
name: "TestRunnerControlsTest"
|
||||||
|
when: windowShown
|
||||||
|
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: testedComponent
|
||||||
|
|
||||||
|
TestRunnerControls {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: sampleLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color errorColor: "darkred"
|
||||||
|
readonly property color successColor: "darkgreen"
|
||||||
|
|
||||||
|
function test_states() {
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.Base
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, false)
|
||||||
|
compare(progressBar.visible, false)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Run tests")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.InProgress
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, true)
|
||||||
|
compare(label.text, "Running tests")
|
||||||
|
compare(label.color, sampleLabel.color)
|
||||||
|
compare(progressBar.visible, true)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Abort")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.Failed,
|
||||||
|
numberOfFailedTests: 42
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, true)
|
||||||
|
compare(label.text, "Tests failed (42)")
|
||||||
|
compare(label.color, root.errorColor)
|
||||||
|
compare(progressBar.visible, false)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Re-run tests")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.Success
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, true)
|
||||||
|
compare(label.text, "Tests passed")
|
||||||
|
compare(label.color, root.successColor)
|
||||||
|
compare(progressBar.visible, false)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Re-run tests")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.Aborted
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, true)
|
||||||
|
compare(label.text, "Tests aborted")
|
||||||
|
compare(label.color, root.errorColor)
|
||||||
|
compare(progressBar.visible, false)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Re-run tests")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const obj = createTemporaryObject(testedComponent, this, {
|
||||||
|
mode: TestRunnerControls.Mode.Crashed
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = findChild(obj, "label")
|
||||||
|
const progressBar = findChild(obj, "progressBar")
|
||||||
|
const button = findChild(obj, "button")
|
||||||
|
|
||||||
|
compare(label.visible, true)
|
||||||
|
compare(label.text, "Tests crashed (segfault)")
|
||||||
|
compare(label.color, root.errorColor)
|
||||||
|
compare(progressBar.visible, false)
|
||||||
|
compare(button.visible, true)
|
||||||
|
compare(button.text, "Re-run tests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ import QtQuick 2.14
|
||||||
import QtQuick.Controls 2.14
|
import QtQuick.Controls 2.14
|
||||||
import QtQuick.Layouts 1.14
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
ToolBar {
|
ToolBar {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -54,6 +56,56 @@ ToolBar {
|
||||||
|
|
||||||
ToolSeparator {}
|
ToolSeparator {}
|
||||||
|
|
||||||
|
TestRunnerControls {
|
||||||
|
id: testRunnerControls
|
||||||
|
|
||||||
|
property var testProcess: null
|
||||||
|
readonly property string testFileName: `tst_${root.componentName}.qml`
|
||||||
|
|
||||||
|
onTestFileNameChanged: {
|
||||||
|
if (testRunnerControls.testProcess)
|
||||||
|
testRunnerControls.testProcess.kill()
|
||||||
|
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.Base
|
||||||
|
}
|
||||||
|
|
||||||
|
onRunClicked: {
|
||||||
|
const testsCount = TestsRunner.testsCount(testFileName)
|
||||||
|
|
||||||
|
if (testsCount === 0)
|
||||||
|
return noTestsDialog.open()
|
||||||
|
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.InProgress
|
||||||
|
|
||||||
|
const process = TestsRunner.runTests(testFileName)
|
||||||
|
testRunnerControls.testProcess = process
|
||||||
|
|
||||||
|
process.finished.connect((exitCode, exitStatus) => {
|
||||||
|
if (testRunnerControls.mode !== TestRunnerControls.Mode.InProgress)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (exitStatus) {
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.Crashed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exitCode)
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.Failed
|
||||||
|
else
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.Success
|
||||||
|
|
||||||
|
testRunnerControls.numberOfFailedTests = exitCode
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onAbortClicked: {
|
||||||
|
testRunnerControls.testProcess.kill()
|
||||||
|
testRunnerControls.mode = TestRunnerControls.Mode.Aborted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolSeparator {}
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: openFigmaButton
|
id: openFigmaButton
|
||||||
|
|
||||||
|
@ -72,4 +124,21 @@ ToolBar {
|
||||||
onClicked: root.inspectClicked()
|
onClicked: root.inspectClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: noTestsDialog
|
||||||
|
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
|
||||||
|
title: "No tests found"
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
|
||||||
|
Label {
|
||||||
|
// check on visible used as a workaround to avoid warning about
|
||||||
|
// binding loop on implicitWidth
|
||||||
|
text: visible
|
||||||
|
? `Please add valid tests to <b>${testRunnerControls.testFileName}</b> file`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
Base,
|
||||||
|
InProgress,
|
||||||
|
Failed,
|
||||||
|
Success,
|
||||||
|
Aborted,
|
||||||
|
Crashed
|
||||||
|
}
|
||||||
|
|
||||||
|
property int mode: TestRunnerControls.Mode.Base
|
||||||
|
property int numberOfFailedTests: 0
|
||||||
|
|
||||||
|
signal runClicked
|
||||||
|
signal abortClicked
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
id: testingRow
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.Base
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: button
|
||||||
|
text: "Run tests"
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.InProgress
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
text: "Running tests"
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: progressBar
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: button
|
||||||
|
text: "Abort"
|
||||||
|
|
||||||
|
onClicked: root.abortClicked()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.Failed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
color: "darkred"
|
||||||
|
text: `Tests failed (${root.numberOfFailedTests})`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.Success
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
color: "darkgreen"
|
||||||
|
text: "Tests passed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.Aborted
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
color: "darkred"
|
||||||
|
text: "Tests aborted"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
when: root.mode === TestRunnerControls.Mode.Crashed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: label
|
||||||
|
color: "darkred"
|
||||||
|
text: "Tests crashed (segfault)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
objectName: "label"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: progressBar
|
||||||
|
|
||||||
|
objectName: "progressBar"
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
indeterminate: true
|
||||||
|
width: 50
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
id: button
|
||||||
|
|
||||||
|
objectName: "button"
|
||||||
|
|
||||||
|
text: "Re-run tests"
|
||||||
|
|
||||||
|
onClicked: root.runClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ PopupBackground 1.0 PopupBackground.qml
|
||||||
SettingsLayout 1.0 SettingsLayout.qml
|
SettingsLayout 1.0 SettingsLayout.qml
|
||||||
SingleItemProxyModel 1.0 SingleItemProxyModel.qml
|
SingleItemProxyModel 1.0 SingleItemProxyModel.qml
|
||||||
SourceCodeBox 1.0 SourceCodeBox.qml
|
SourceCodeBox 1.0 SourceCodeBox.qml
|
||||||
|
TestRunnerControls 1.0 TestRunnerControls.qml
|
||||||
singleton FigmaUtils 1.0 FigmaUtils.qml
|
singleton FigmaUtils 1.0 FigmaUtils.qml
|
||||||
singleton InspectionUtils 1.0 InspectionUtils.qml
|
singleton InspectionUtils 1.0 InspectionUtils.qml
|
||||||
singleton StorybookUtils 1.0 StorybookUtils.qml
|
singleton StorybookUtils 1.0 StorybookUtils.qml
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
#include "testsrunner.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
TestsRunner::TestsRunner(const QString& testRunnerExecutablePath,
|
||||||
|
const QString& testsBasePath, QObject* parent)
|
||||||
|
: QObject{parent}, m_testRunnerExecutablePath{testRunnerExecutablePath},
|
||||||
|
m_testsBasePath{testsBasePath}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TestsRunner::testsCount(const QString& fileName)
|
||||||
|
{
|
||||||
|
QStringList arguments;
|
||||||
|
arguments << QStringLiteral("-functions");
|
||||||
|
arguments << QStringLiteral("-input")
|
||||||
|
<< m_testsBasePath + QDir::separator() + fileName;
|
||||||
|
|
||||||
|
QProcess testRunnerProcess;
|
||||||
|
testRunnerProcess.setProgram(m_testRunnerExecutablePath);
|
||||||
|
testRunnerProcess.setArguments(arguments);
|
||||||
|
testRunnerProcess.open(QIODevice::Text | QIODevice::ReadWrite);
|
||||||
|
testRunnerProcess.waitForFinished();
|
||||||
|
|
||||||
|
if (testRunnerProcess.exitCode())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
QByteArray functions = testRunnerProcess.readAllStandardError();
|
||||||
|
return functions.count('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* TestsRunner::runTests(const QString& fileName)
|
||||||
|
{
|
||||||
|
QStringList arguments;
|
||||||
|
arguments << QStringLiteral("-platform") << QStringLiteral("offscreen");
|
||||||
|
arguments << QStringLiteral("-input")
|
||||||
|
<< m_testsBasePath + QDir::separator() + fileName;
|
||||||
|
|
||||||
|
QProcess *testRunnerProcess = new QProcess(this);
|
||||||
|
testRunnerProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
testRunnerProcess->start(m_testRunnerExecutablePath, arguments);
|
||||||
|
|
||||||
|
using FinishHandlerType = void (QProcess::*)(int, QProcess::ExitStatus);
|
||||||
|
|
||||||
|
connect(testRunnerProcess,
|
||||||
|
static_cast<FinishHandlerType>(&QProcess::finished),
|
||||||
|
testRunnerProcess, &QObject::deleteLater);
|
||||||
|
|
||||||
|
return testRunnerProcess;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class TestsRunner : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TestsRunner(const QString& testRunnerExecutablePath,
|
||||||
|
const QString& testsPath, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
Q_INVOKABLE int testsCount(const QString& path);
|
||||||
|
Q_INVOKABLE QObject* runTests(const QString& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_testRunnerExecutablePath;
|
||||||
|
QString m_testsBasePath;
|
||||||
|
};
|
Loading…
Reference in New Issue