aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-24 10:45:32 +0200
committerDanilo M. <danix@danix.xyz>2026-08-24 10:45:32 +0200
commit22f01049b03f3a6bbe0455f96105a73d37abb3ee (patch)
tree6c25a41f43acc1d4bf5d7d831590e05eb60f6151 /tests
parentdf5f64f16359c9e34d258758f174187ffc618101 (diff)
downloadqtmaildir-22f01049b03f3a6bbe0455f96105a73d37abb3ee.tar.gz
qtmaildir-22f01049b03f3a6bbe0455f96105a73d37abb3ee.zip
fix(messageview): drop the receive-only ribbon when the pane is blanked
MessageView::clear() resets the blocked-content bar, the stale notice and the attachment bar by hand, and forgot the receive-only ribbon. Only setReceiveOnlyAccount() ever hid it, and that is reached from updateComposeActions(), which runs on a SELECTION change. So the ribbon survived every route to a blank pane that is not one: clear_pane, clear_selection, a new query, and a multi-row selection. It sat over a blank pane, or over another account's mail, naming an account that was no longer on screen and contradicting the live Reply button beside it. Worth recording because it cost a test: the first one written for this selected receive-only mail and then mail from a sending account, which is how the report reads. It passed against the unfixed code, because that gesture is precisely the one path that was already covered. The test now drives clear_pane and a new query as well. Its own trap, in the test rather than the code: clear_pane leaves the row CURRENT, so re-selecting it emits no change and the ribbon is never re-raised. The test moves away and back instead.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_mainwindow.cpp96
1 files changed, 96 insertions, 0 deletions
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp
index 91fbd44..9e4543c 100644
--- a/tests/test_mainwindow.cpp
+++ b/tests/test_mainwindow.cpp
@@ -257,6 +257,7 @@ private slots:
void theMailRootComesFromTheConfigNotTheIndex();
void replyIsDisabledOnAReceiveOnlyAccountsMail();
void theReceiveOnlyRibbonNamesTheAccount();
+ void theReceiveOnlyRibbonGoesWithTheMessageThatRaisedIt();
void replyIsEnabledOnASendingAccountsMail();
void composeIsDisabledOnlyWhenNoAccountCanSend();
void quittingWithACleanComposerAsksNothing();
@@ -8431,6 +8432,101 @@ void TestMainWindow::theReceiveOnlyRibbonNamesTheAccount()
QCOMPARE(ribbon->textFormat(), Qt::PlainText);
}
+void TestMainWindow::theReceiveOnlyRibbonGoesWithTheMessageThatRaisedIt()
+{
+ // The ribbon explains ONE message, so it must not outlive it. Observed in
+ // All accounts: receive-only mail raised it, and selecting mail from an
+ // account that can send left it on screen contradicting the live Reply
+ // button beside it.
+ WorkerComposeFixture fixture;
+ QVERIFY(fixture.backed.fixture().addMessage(
+ QStringLiteral("listsonly/inbox"), QStringLiteral("ro@example.org"),
+ QStringLiteral("Receive only"), QStringLiteral("sender@example.org"),
+ QStringLiteral("Fri, 14 Aug 2026 10:00:00 +0200"),
+ QStringLiteral("Body text.")));
+ QVERIFY(fixture.backed.fixture().addMessage(
+ QStringLiteral("work/inbox"), QStringLiteral("rw@example.org"),
+ QStringLiteral("Can send"), QStringLiteral("sender@example.org"),
+ QStringLiteral("Fri, 14 Aug 2026 11:00:00 +0200"),
+ QStringLiteral("Body text.")));
+ QVERIFY2(fixture.backed.buildWithAccounts(
+ { { QStringLiteral("listsonly"), QStringLiteral("listsonly"),
+ QString(), QString(), QStringLiteral("you@example.org") },
+ { QStringLiteral("work"), QStringLiteral("work"),
+ QString(), QStringLiteral("/bin/true"),
+ QStringLiteral("you@example.org") } }),
+ qPrintable(fixture.backed.error()));
+
+ MainWindow window(fixture.backed.config());
+ auto *model = window.findChild<ThreadListModel *>();
+ auto *view = window.findChild<ThreadListView *>();
+ auto *queryEdit =
+ window.findChild<QLineEdit *>(QStringLiteral("queryEdit"));
+ auto *ribbon =
+ window.findChild<QLabel *>(QStringLiteral("receiveOnlyRibbon"));
+ QVERIFY(model && view && queryEdit && ribbon);
+
+ // Both messages in one list, which is the All accounts view the defect was
+ // seen in. The mail root has to have arrived too: the ribbon is decided by
+ // which account owns the message, which cannot be answered without it.
+ queryEdit->setText(QStringLiteral("tag:inbox"));
+ queryEdit->returnPressed();
+ QTRY_VERIFY_WITH_TIMEOUT(model->rowCount(QModelIndex()) == 2
+ && !window.mailRootForTesting().isEmpty(),
+ 15000);
+
+ // Find each row by subject rather than by position: the sort order is not
+ // what is under test, and asserting on it would make this fail for a
+ // reason that has nothing to do with the ribbon.
+ QModelIndex receiveOnlyRow;
+ QModelIndex sendingRow;
+ for (int row = 0; row < model->rowCount(QModelIndex()); ++row) {
+ const QModelIndex index = model->index(row, 0, QModelIndex());
+ const QString subject = model->threadFor(index).subject;
+ if (subject == QStringLiteral("Receive only"))
+ receiveOnlyRow = index;
+ else if (subject == QStringLiteral("Can send"))
+ sendingRow = index;
+ }
+ QVERIFY2(receiveOnlyRow.isValid() && sendingRow.isValid(),
+ "the two seeded messages are not both in the list");
+
+ view->setCurrentIndex(receiveOnlyRow);
+ QTRY_VERIFY_WITH_TIMEOUT(!ribbon->isHidden(), 15000);
+
+ // Straight from one to the other, with no deselection in between. This
+ // half already worked: a selection change reaches updateComposeActions().
+ view->setCurrentIndex(sendingRow);
+ QTRY_VERIFY_WITH_TIMEOUT(ribbon->isHidden(), 15000);
+ QVERIFY2(ribbon->isHidden(),
+ "the ribbon stayed up on mail from an account that can send");
+
+ // The half that did not: blanking the pane by any route that is not a
+ // selection change. MessageView::clear() resets the blocked-content bar,
+ // the stale notice and the attachment bar by hand, and forgot this one, so
+ // the ribbon outlived the message it explains.
+ view->setCurrentIndex(receiveOnlyRow);
+ QTRY_VERIFY_WITH_TIMEOUT(!ribbon->isHidden(), 15000);
+
+ window.findChild<QAction *>(QStringLiteral("clear_pane"))->trigger();
+ QVERIFY2(ribbon->isHidden(),
+ "the ribbon survived clear_pane, over a blank message pane");
+
+ // Away and back, not straight back: clear_pane leaves the receive-only row
+ // CURRENT, so re-selecting it emits no change and the ribbon would never
+ // be re-raised. That is the view's behaviour and not the defect under test.
+ view->setCurrentIndex(sendingRow);
+ QTRY_VERIFY_WITH_TIMEOUT(ribbon->isHidden(), 15000);
+ view->setCurrentIndex(receiveOnlyRow);
+ QTRY_VERIFY_WITH_TIMEOUT(!ribbon->isHidden(), 15000);
+
+ queryEdit->setText(QStringLiteral("tag:inbox and subject:\"Can send\""));
+ queryEdit->returnPressed();
+ QTRY_VERIFY_WITH_TIMEOUT(model->rowCount(QModelIndex()) == 1, 15000);
+ QVERIFY2(ribbon->isHidden(),
+ "the ribbon survived a new query that blanked the pane");
+}
+
void TestMainWindow::composeIsDisabledOnlyWhenNoAccountCanSend()
{
// An installation with no send_command anywhere is a valid read-only