a device run can be looked at: --shots, and Qt's messages in the log

The settings dialog check failed only on the phone, with no QML error and
nothing to read: this build's Qt messages never reach logcat (verified: a
plain qInfo from the app is not in the buffer). Two ways in, then:

- --uitest installs a message handler that writes Qt's own warnings into
  uitest.log, next to the checks. What the phone did say, it says there.
- --uitest --shots saves window grabs at the interesting points into the
  workspace. A device run cannot be handed CST_APP_SHOT (an app started
  from adb gets no environment), so what a desktop run asks for with an
  environment variable has to be an argument here. main.cpp takes it, so
  `--uitest --workspace DIR --shots` works from adb.

What they said about the phone (NX789J, 1280x853):

  ok ... the gear is reachable, centre 1191,56 of 1280x853
  ok ... and openSettings() opens it when called directly

so the button is there and the handler works: the synthesized click is what
does not open the dialog. The run's own picture of that moment shows why --
the header is drawn over the sidebar, so the click lands on what is drawn
above the gear. On a desktop the same window has the header above the
sidebar and the click lands. Not fixed yet (nor the Open/Share checks on the
device, which are the other two failures that are not about the dialog).

The settings checks now go on either way, so a phone run reports the dialog
instead of eleven lines of "not there".
This commit is contained in:
WHC
2026-10-11 20:53:16 +08:00
parent a34c74e453
commit f8030ec201
2 changed files with 60 additions and 0 deletions
+14
View File
@@ -193,12 +193,20 @@ int main(int argc, char **argv) {
QCommandLineOption sizeOpt(QStringLiteral("size"),
QStringLiteral("initial window size, e.g. 480x900"),
QStringLiteral("WxH"));
/* A device run cannot be handed an environment (see activityArguments()), so
* what a desktop run asks for with CST_APP_SHOT=shot.png has to be an
* argument here. */
QCommandLineOption shotsOpt(
QStringLiteral("shots"),
QStringLiteral("--uitest: save a picture of the window at the interesting "
"points, in the workspace"));
parser.addOption(wsOpt);
parser.addOption(providerOpt);
parser.addOption(modelOpt);
parser.addOption(planOpt);
parser.addOption(uitestOpt);
parser.addOption(sizeOpt);
parser.addOption(shotsOpt);
/* What the process was started with, plus -- on a phone -- what the
* activity was started with: Qt's own applicationArguments plumbing does
* not deliver the extra on the NX789J (see activityArguments()), and
@@ -235,6 +243,12 @@ int main(int argc, char **argv) {
}
}
/* Before the window exists: maybeShot() reads this at the point a picture is
* wanted (the settings dialog, the end of the run). */
if (parser.isSet(shotsOpt))
qputenv("CST_APP_SHOT",
(ws + QStringLiteral("/uitest-shot.png")).toUtf8());
#if defined(Q_OS_ANDROID)
/* Before the engine is created: its settings, credentials and session store
* all resolve their paths from the environment. */
+46
View File
@@ -29,6 +29,7 @@
#include <QVariantMap>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
@@ -51,6 +52,27 @@ int g_fail;
* file could not be made, in which case the run only prints. */
QFile g_runLog;
/* Qt's own messages go into the same log as the checks: this is where QML
* puts "TypeError: Cannot read property ... of undefined" and every other
* reason a step did nothing, and a device run has nowhere else to show it
* (logcat does not carry this build's Qt messages -- a plain qInfo from the
* app is not in the buffer). Messages before the log is opened still print. */
void logQtMessage(QtMsgType type, const QMessageLogContext &, const QString &msg) {
const char *kind = type == QtDebugMsg ? "debug"
: type == QtInfoMsg ? "info"
: type == QtWarningMsg ? "warn"
: type == QtCriticalMsg ? "crit"
: "fatal";
const QByteArray line = QByteArray(kind) + " " + msg.toUtf8() + "\n";
if (g_runLog.isOpen()) {
g_runLog.write(line);
g_runLog.flush();
}
fwrite(line.constData(), 1, static_cast<size_t>(line.size()), stderr);
if (type == QtFatalMsg)
abort();
}
void check(bool ok, const QString &what) {
std::printf("%s %s\n", ok ? "ok " : "FAIL", qPrintable(what));
std::fflush(stdout);
@@ -262,6 +284,7 @@ int runUiTest(AgentCore &core, const QString &size) {
* makes, so a device run can be read back without logcat (see g_runLog). */
g_runLog.setFileName(core.workspace() + QStringLiteral("/uitest.log"));
g_runLog.open(QIODevice::WriteOnly | QIODevice::Truncate);
qInstallMessageHandler(logQtMessage);
const QString resumed =
writeFixtureSession(core.workspace(), QStringLiteral("20260101-115959-on"));
check(!resumed.isEmpty() && core.switchSession(resumed),
@@ -642,6 +665,29 @@ int runUiTest(AgentCore &core, const QString &size) {
clickMouse(win, QStringLiteral("settingsButton"));
QQuickItem *panel = item(win, QStringLiteral("settingsPanel"));
check(panel && panel->isVisible(), QStringLiteral("the gear opens the settings dialog"));
/* item() answers with an item that exists even when nothing is visible (the
* QObject-tree fallback), so "the dialog is not open" is the invisible case
* too. */
if (!panel || !panel->isVisible()) {
/* Two ways to be wrong -- a click that never lands, and a handler that
* does nothing -- and from the outside they look the same (this failed
* only on the phone, with no QML error at all). Say which, and go on with
* the dialog either way, so the checks below still say something. */
QQuickItem *gear = item(win, QStringLiteral("settingsButton"));
check(gear != nullptr && gear->isVisible(),
QStringLiteral("... the gear is %1, centre %2,%3 of %4x%5")
.arg(gear && gear->isVisible() ? QStringLiteral("reachable")
: QStringLiteral("not there"))
.arg(gear ? centre(gear).x() : -1)
.arg(gear ? centre(gear).y() : -1)
.arg(win->width())
.arg(win->height()));
QMetaObject::invokeMethod(win, "openSettings");
QTest::qWait(120);
panel = item(win, QStringLiteral("settingsPanel"));
check(panel && panel->isVisible(),
QStringLiteral("... and openSettings() opens it when called directly"));
}
check(countNamed(win->contentItem(), QStringLiteral("providerRow:")) > 0,
QStringLiteral("the dialog lists the providers"));
maybeShot(win, QStringLiteral("-settings"));