tests(StatusInput): add regression test to check for qml output
Also improves on the test structure
This commit is contained in:
parent
b0c00fd60d
commit
8d780bb5b9
|
@ -16,3 +16,4 @@ sandbox/qmlcache_loader.cpp
|
|||
doc/html
|
||||
CMakeLists.txt.user
|
||||
.vscode
|
||||
build/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(TestStatusInputWithRegex LANGUAGES CXX)
|
||||
project(TestControls LANGUAGES CXX)
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
@ -9,8 +9,8 @@ list(APPEND QML_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")
|
|||
set(QML_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths")
|
||||
set(QML2_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths")
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS QuickTest Qml REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS QuickTest Qml REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS QuickTest Qml Quick REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS QuickTest Qml Quick REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
|
@ -24,10 +24,20 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||
# no need to copy around qml test files for shadow builds - just set the respective define
|
||||
add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
add_executable(TestStatusInputWithRegex main.cpp)
|
||||
add_test(NAME TestStatusInputWithRegex COMMAND TestStatusInputWithRegex)
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
|
||||
|
||||
target_link_libraries(TestStatusInputWithRegex PRIVATE
|
||||
# TODO: move this to a test helpers library
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_subdirectory(TestHelpers)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::QuickTest
|
||||
Qt${QT_VERSION_MAJOR}::Qml)
|
||||
Qt${QT_VERSION_MAJOR}::Qml
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
pragma Singleton
|
||||
|
||||
import QtQml 2.14
|
||||
import QtTest 1.0
|
||||
|
||||
QtObject {
|
||||
|
||||
//> Simulate key and wait for side effects
|
||||
function pressKeyAndWait(test, item, key) {
|
||||
test.keyClick(key)
|
||||
|
||||
test.waitForRendering(item)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module StatusQ.TestHelpers
|
||||
|
||||
singleton TestUtils 0.1 TestUtils.qml
|
|
@ -0,0 +1,12 @@
|
|||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
#include "MonitorQtOutput.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing;
|
||||
std::mutex MonitorQtOutput::m_mutex;
|
||||
|
||||
|
||||
MonitorQtOutput::MonitorQtOutput()
|
||||
{
|
||||
// Ensure only one instance registers a handler
|
||||
// Warning: don't QT's call loger functions inside the critical section
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
auto globalMsgOut = m_qtMessageOutputForSharing.lock();
|
||||
if(!globalMsgOut) {
|
||||
// Install message handler if not already done
|
||||
m_thisMessageOutput = std::make_shared<QString>();
|
||||
m_qtMessageOutputForSharing = m_thisMessageOutput;
|
||||
qInstallMessageHandler(qtMessageOutput);
|
||||
}
|
||||
else {
|
||||
m_thisMessageOutput = globalMsgOut;
|
||||
m_start = m_thisMessageOutput->length();
|
||||
}
|
||||
}
|
||||
|
||||
MonitorQtOutput::~MonitorQtOutput()
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
if(m_thisMessageOutput.use_count() == 1) {
|
||||
// Last instance, deregister the handler
|
||||
qInstallMessageHandler(0);
|
||||
m_thisMessageOutput.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
auto globalMsgOut = m_qtMessageOutputForSharing.lock();
|
||||
assert(globalMsgOut != nullptr);
|
||||
globalMsgOut->append(msg + '\n');
|
||||
}
|
||||
|
||||
QString
|
||||
MonitorQtOutput::qtOuput()
|
||||
{
|
||||
assert(m_thisMessageOutput->length() >= m_start);
|
||||
return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
///
|
||||
/// \brief Monitor output for tests and declarativelly control message handler availability
|
||||
/// \todo Check that QML doesn't keep instance between test runs
|
||||
///
|
||||
class MonitorQtOutput : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MonitorQtOutput();
|
||||
~MonitorQtOutput();
|
||||
|
||||
Q_INVOKABLE QString qtOuput();
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
static void qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
|
||||
// Use it to keep track of qInstallMessageHandler call
|
||||
static std::weak_ptr<QString> m_qtMessageOutputForSharing;
|
||||
static std::mutex m_mutex;
|
||||
std::shared_ptr<QString> m_thisMessageOutput;
|
||||
int m_start = 0;
|
||||
};
|
|
@ -1,6 +1,8 @@
|
|||
#include <QtQuickTest/quicktest.h>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "TestHelpers/MonitorQtOutput.h"
|
||||
|
||||
class TestSetup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -13,7 +15,12 @@ public slots:
|
|||
{
|
||||
// TODO: Workaround until we make StatusQ a CMake library
|
||||
engine->addImportPath("../../src/");
|
||||
engine->addImportPath(".");
|
||||
// TODO: Alternative to not yet supported QML_ELEMENT
|
||||
qmlRegisterType<MonitorQtOutput>("StatusQ.TestHelpers", 0, 1, "MonitorQtOutput");
|
||||
}
|
||||
private:
|
||||
MonitorQtOutput _monitorOutput;
|
||||
};
|
||||
|
||||
QUICK_TEST_MAIN_WITH_SETUP(TestControls, TestSetup)
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import QtQuick 2.0
|
||||
import QtTest 1.0
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
|
||||
import StatusQ.TestHelpers 0.1
|
||||
|
||||
Item {
|
||||
width: 300
|
||||
height: 100
|
||||
|
||||
StatusBaseInput {
|
||||
id: statusInput
|
||||
text: "Control under test"
|
||||
placeholderText: "Placeholder"
|
||||
focus: true
|
||||
}
|
||||
|
||||
TestCase {
|
||||
id: testCase
|
||||
name: "CheckQmlWarnings"
|
||||
|
||||
when: windowShown
|
||||
|
||||
//
|
||||
// Test guards
|
||||
|
||||
function initTestCase() {
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
statusInput.text = ""
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
|
||||
function test_initial_empty_is_valid() {
|
||||
mouseClick(statusInput)
|
||||
// Do some editing
|
||||
TestUtils.pressKeyAndWait(testCase, statusInput, Qt.Key_B)
|
||||
TestUtils.pressKeyAndWait(testCase, statusInput, Qt.Key_Left)
|
||||
TestUtils.pressKeyAndWait(testCase, statusInput, Qt.Key_A)
|
||||
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||
}
|
||||
}
|
||||
|
||||
MonitorQtOutput {
|
||||
id: qtOuput
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ import QtTest 1.0
|
|||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
|
||||
import StatusQ.TestHelpers 0.1
|
||||
|
||||
Item {
|
||||
width: 300
|
||||
height: 100
|
||||
|
@ -28,6 +30,8 @@ Item {
|
|||
}
|
||||
|
||||
TestCase {
|
||||
id: regexTC
|
||||
|
||||
name: "RegexValidationTest"
|
||||
|
||||
when: windowShown
|
||||
|
@ -50,9 +54,9 @@ Item {
|
|||
}
|
||||
|
||||
function test_regex_validation() {
|
||||
keyClick(Qt.Key_1)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_1)
|
||||
verify(statusInput.valid, "Expected valid input")
|
||||
keyClick(Qt.Key_Ampersand)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Ampersand)
|
||||
verify(!statusInput.valid, "Expected invalid input")
|
||||
}
|
||||
|
||||
|
@ -61,10 +65,10 @@ Item {
|
|||
|
||||
verify(statusInput.valid, "Expected valid input")
|
||||
verify(statusInput.text.length === 0, "Expected no input")
|
||||
keyClick(Qt.Key_2)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_2)
|
||||
verify(statusInput.valid, "Expected valid input")
|
||||
verify(statusInput.text === "2", "Expect one character")
|
||||
keyClick(Qt.Key_Ampersand)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Ampersand)
|
||||
verify(statusInput.valid, "Expected invalid input")
|
||||
verify(statusInput.text === "2", "Expect the same input")
|
||||
}
|
||||
|
@ -74,12 +78,43 @@ Item {
|
|||
const appendInvalidChars = "#@!*"
|
||||
|
||||
statusInput.text = "invalid $" + appendInvalidChars
|
||||
keyClick(Qt.Key_End)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_End)
|
||||
verify(!statusInput.valid, "Expected invalid input due to characters not matching")
|
||||
// Delete invalid characters to get a valid text
|
||||
for(let i = 0; i < appendInvalidChars.length; ++i)
|
||||
keyClick(Qt.Key_Backspace)
|
||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Backspace)
|
||||
verify(statusInput.valid, "Expected valid input")
|
||||
}
|
||||
}
|
||||
|
||||
TestCase {
|
||||
id: qmlWarnTC
|
||||
|
||||
name: "CheckQmlWarnings"
|
||||
|
||||
when: windowShown
|
||||
|
||||
//
|
||||
// Test guards
|
||||
|
||||
function initTestCase() {
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
statusInput.text = ""
|
||||
statusInput.validationMode = _defaultValidationMode
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
|
||||
function test_initial_empty_is_valid() {
|
||||
mouseClick(statusInput)
|
||||
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||
}
|
||||
}
|
||||
|
||||
MonitorQtOutput {
|
||||
id: qtOuput
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# Readme
|
||||
|
||||
## Developer instructions
|
||||
|
||||
CMake
|
||||
|
||||
```sh
|
||||
cd StatusQ/tests/TestControls
|
||||
cmake -B ./build/ -S .
|
||||
cmake --build ./build/
|
||||
./build/TestControls
|
||||
```
|
||||
|
||||
QtCreator
|
||||
|
||||
- Open the StatusQ/tests/CMakeLists.txt
|
||||
- Choose a QT kit to run the tests
|
||||
- In the `Test Results` panel choose Run All Tests
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Consolidate and integrate with https://github.com/status-im/desktop-ui-tests
|
Loading…
Reference in New Issue