1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#ifndef DIALOGSTESTUTILS_H
5#define DIALOGSTESTUTILS_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
19
20#include <QtQuickTest/QtQuickTest>
21#include <QtQuickTestUtils/private/qmlutils_p.h>
22#include <QtQuickTestUtils/private/visualtestutils_p.h>
23
24// We need these for Windows, because FolderListModel returns a lowercase drive letter; e.g.:
25// "file:///c:/blah.txt", whereas other API returns "file:///C:/blah.txt".
26#define COMPARE_URL(url1, url2) \
27 QCOMPARE(QFileInfo(url1.toLocalFile()).absoluteFilePath(), QFileInfo(url2.toLocalFile()).absoluteFilePath());
28
29// Store a copy of the arguments in case { ... } list initializer syntax is used as an argument,
30// which could result in two different lists being created and passed to std::transform()
31// (and would also require it to be enclosed in parentheses everywhere it's used).
32#define COMPARE_URLS(actualUrls, expectedUrls) \
33{ \
34 const QList<QUrl> actualUrlsCopy = actualUrls; \
35 QList<QString> actualPaths; \
36 std::transform(actualUrlsCopy.begin(), actualUrlsCopy.end(), std::back_insert_iterator(actualPaths), \
37 [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
38 const QList<QUrl> expectedUrlsCopy = expectedUrls; \
39 QList<QString> expectedPaths; \
40 std::transform(expectedUrlsCopy.begin(), expectedUrlsCopy.end(), std::back_insert_iterator(expectedPaths), \
41 [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
42 QCOMPARE(actualPaths, expectedPaths); \
43}
44
45#define OPEN_QUICK_DIALOG() \
46QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage()); \
47QVERIFY(dialogHelper.waitForWindowActive()); \
48QVERIFY(dialogHelper.openDialog()); \
49QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
50
51#define CLOSE_QUICK_DIALOG() \
52 do { \
53 dialogHelper.dialog->close(); \
54 QVERIFY(!dialogHelper.dialog->isVisible()); \
55 QTRY_VERIFY(!dialogHelper.quickDialog->isVisible()); \
56 } while (false)
57
58QT_BEGIN_NAMESPACE
59class QWindow;
60
61class QQuickListView;
62
63class QQuickAbstractButton;
64
65class QQuickDialogButtonBox;
66class QQuickFolderBreadcrumbBar;
67
68namespace QQuickDialogTestUtils
69{
70
71// Saves duplicating a bunch of code in every test.
72template<typename DialogType, typename QuickDialogType>
73class DialogTestHelper
74{
75public:
76 DialogTestHelper(QQmlDataTest *testCase, const QString &testFilePath,
77 const QStringList &qmlImportPaths = {}, const QVariantMap &initialProperties = {}) :
78 appHelper(testCase, testFilePath, initialProperties, qmlImportPaths)
79 {
80 if (!appHelper.ready)
81 return;
82
83 dialog = appHelper.window->property(name: "dialog").value<DialogType*>();
84 if (!dialog) {
85 appHelper.errorMessage = "\"dialog\" property is not valid";
86 return;
87 }
88
89 appHelper.window->show();
90 appHelper.window->requestActivate();
91 }
92
93 Q_REQUIRED_RESULT bool isWindowInitialized() const
94 {
95 return appHelper.ready;
96 }
97
98 Q_REQUIRED_RESULT bool waitForWindowActive()
99 {
100 return QTest::qWaitForWindowActive(window: appHelper.window);
101 }
102
103 /*
104 Opens the dialog. For non-native dialogs, it is necessary to ensure that
105 isQuickDialogOpen() returns true before trying to access its internals.
106 */
107 virtual bool openDialog()
108 {
109 dialog->open();
110 if (!dialog->isVisible()) {
111 appHelper.errorMessage = "Dialog is not visible";
112 return false;
113 }
114
115 // We might want to call this function more than once,
116 // and we only need to get these members the first time.
117 if (!quickDialog) {
118 quickDialog = appHelper.window->findChild<QuickDialogType*>();
119 if (!quickDialog) {
120 appHelper.errorMessage = "Can't find Qt Quick-based dialog";
121 return false;
122 }
123 }
124
125 return true;
126 }
127
128 QQuickWindow *popupWindow() const
129 {
130 return quickDialog->contentItem()->window();
131 }
132
133 Q_REQUIRED_RESULT bool waitForPopupWindowActiveAndPolished()
134 {
135 if (!isQuickDialogOpen()) {
136 QByteArray msg("Dialog wasn't open, when {} was called");
137 msg.replace("{}", __func__);
138 appHelper.errorMessage = msg;
139 return false;
140 }
141 QQuickWindow *dialogPopupWindow = popupWindow();
142 if (!dialogPopupWindow)
143 return false;
144 dialogPopupWindow->requestActivate();
145 if (!QTest::qWaitForWindowActive(window: dialogPopupWindow))
146 return false;
147 return QQuickTest::qWaitForPolish(window: dialogPopupWindow);
148 }
149
150 bool isQuickDialogOpen() const
151 {
152 return quickDialog->isOpened();
153 }
154
155 QQuickWindow *window() const
156 {
157 return appHelper.window;
158 }
159
160 const char *failureMessage() const
161 {
162 return appHelper.errorMessage.constData();
163 }
164
165 QQuickVisualTestUtils::QQuickApplicationHelper appHelper;
166 DialogType *dialog = nullptr;
167 QuickDialogType *quickDialog = nullptr;
168};
169
170bool verifyFileDialogDelegates(QQuickListView *fileDialogListView, const QStringList &expectedFiles, QString &failureMessage);
171
172bool verifyBreadcrumbDelegates(QQuickFolderBreadcrumbBar *breadcrumbBar, const QUrl &expectedFolder, QString &failureMessage);
173
174QQuickAbstractButton *findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText);
175
176void enterText(QWindow *window, const QString &textToEnter);
177}
178
179QT_END_NAMESPACE
180
181#endif // DIALOGSTESTUTILS_H
182

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quickcontrolstestutils/dialogstestutils_p.h