aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_messageview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_messageview.cpp')
-rw-r--r--tests/test_messageview.cpp80
1 files changed, 80 insertions, 0 deletions
diff --git a/tests/test_messageview.cpp b/tests/test_messageview.cpp
index c97a216..87234aa 100644
--- a/tests/test_messageview.cpp
+++ b/tests/test_messageview.cpp
@@ -17,8 +17,10 @@
*/
#include <QLabel>
+#include <QMenu>
#include <QPushButton>
#include <QSignalSpy>
+#include <QWebEnginePage>
#include <QWebEngineUrlScheme>
#include <QWebEngineView>
#include <QtTest>
@@ -54,6 +56,7 @@ private slots:
void headerOffersNoSenderForARealThread();
void headerOffersNothingForAnAbsentField();
void bodySelectionBecomesAQuotedSearch();
+ void theBodyMenuDropsTheBrowsersOwnActions();
void aSearchFromTheDetailsDialogClosesIt();
private:
@@ -699,6 +702,83 @@ void TestMessageView::bodySelectionBecomesAQuotedSearch()
.label.isEmpty());
}
+void TestMessageView::theBodyMenuDropsTheBrowsersOwnActions()
+{
+ // Item 100. The pane starts from Chromium's standard context menu, which
+ // is built for a browser: Back, Forward, Reload, Save page and View source
+ // all arrive with it and none of them can apply, since every document
+ // comes through setHtml() with a fixed base URL and the interceptor blocks
+ // everything by default.
+ //
+ // Asserted on the ACTION POINTERS, which is also how the production code
+ // matches them. Matching on text would pass here and fail in every locale
+ // but English, and an untranslated match is exactly the defect this could
+ // reintroduce without any test noticing.
+ MessageView view;
+ auto *page = view.findChild<QWebEnginePage *>();
+ QVERIFY2(page, "no page, so this test would assert nothing");
+
+ QMenu menu;
+ const QList<QWebEnginePage::WebAction> unwanted = {
+ QWebEnginePage::Back, QWebEnginePage::Forward,
+ QWebEnginePage::Reload, QWebEnginePage::SavePage,
+ };
+ // Kept, and the reason the standard menu is used at all rather than being
+ // rebuilt from scratch.
+ //
+ // ViewSource is in this list deliberately. It was removed with the four
+ // above at first, which was an overreach: it has a real document and a
+ // real use, and item 113 implements it properly. A test asserting it is
+ // GONE would lock in the overreach, so it asserts it survives.
+ //
+ // SelectAll is deliberately NOT here, and the reason is a limit of this
+ // test worth stating. This menu is built BY HAND, so "SelectAll survives"
+ // would only prove the filter does not remove it, and prove nothing about
+ // whether Chromium's real menu ever offers it. Measured by hand on
+ // 2026-08-17, with a selection active: the real menu holds Copy and the
+ // search entries and no Select all, both before and after this filter
+ // existed. Asserting on it here would read as a guarantee the code does
+ // not make. See item 117.
+ const QList<QWebEnginePage::WebAction> wanted = {
+ QWebEnginePage::Copy,
+ QWebEnginePage::ViewSource,
+ };
+
+ for (const QWebEnginePage::WebAction which : unwanted)
+ menu.addAction(page->action(which));
+ menu.addSeparator();
+ for (const QWebEnginePage::WebAction which : wanted)
+ menu.addAction(page->action(which));
+
+ // The guard: the menu really does hold what the assertions below are about,
+ // so a filter that removed everything, or a page that offered nothing,
+ // cannot pass by accident.
+ QCOMPARE(menu.actions().size(), unwanted.size() + wanted.size() + 1);
+
+ MessageView::removeBrowserActions(&menu, page);
+
+ const QList<QAction *> left = menu.actions();
+ for (const QWebEnginePage::WebAction which : unwanted) {
+ QVERIFY2(!left.contains(page->action(which)),
+ qPrintable(QStringLiteral(
+ "a browser action survived the filter: %1")
+ .arg(page->action(which)->text())));
+ }
+ for (const QWebEnginePage::WebAction which : wanted) {
+ QVERIFY2(left.contains(page->action(which)),
+ qPrintable(QStringLiteral(
+ "the filter removed an action the pane needs: "
+ "%1")
+ .arg(page->action(which)->text())));
+ }
+
+ // No separator left stranded at either edge by the removals, which reads
+ // as a menu that lost something.
+ QVERIFY(!left.isEmpty());
+ QVERIFY(!left.constFirst()->isSeparator());
+ QVERIFY(!left.constLast()->isSeparator());
+}
+
void TestMessageView::aSearchFromTheDetailsDialogClosesIt()
{
// The dialog is modal. Without closing it, the query runs and the thread