From 576a97774e04858adee9f2080e485a715e985820 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 27 Sep 2017 15:14:32 +0200 Subject: Rename tst_menu to tst_QQuickMenu Change-Id: I1c7e1a2b337e9d16bc6c9b098db08f29f1b9d1e6 Reviewed-by: Mitch Curtis --- tests/auto/qquickmenu/tst_qquickmenu.cpp | 482 +++++++++++++++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 tests/auto/qquickmenu/tst_qquickmenu.cpp (limited to 'tests/auto/qquickmenu/tst_qquickmenu.cpp') diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp new file mode 100644 index 00000000..717e892b --- /dev/null +++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp @@ -0,0 +1,482 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +#include +#include +#include +#include +#include +#include + +using namespace QQuickVisualTestUtil; + +class tst_QQuickMenu : public QQmlDataTest +{ + Q_OBJECT + +public: + +private slots: + void defaults(); + void mouse(); + void pressAndHold(); + void contextMenuKeyboard(); + void menuButton(); + void addItem(); + void menuSeparator(); + void repeater(); + void order(); +}; + +void tst_QQuickMenu::defaults() +{ + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value(); + QCOMPARE(emptyMenu->isVisible(), false); + QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1)); +} + +void tst_QQuickMenu::mouse() +{ + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + menu->open(); + QVERIFY(menu->isVisible()); + QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + + QQuickItem *firstItem = menu->itemAt(0); + QSignalSpy clickedSpy(firstItem, SIGNAL(clicked())); + QSignalSpy triggeredSpy(firstItem, SIGNAL(triggered())); + QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged())); + + // Ensure that presses cause the current index to change, + // so that the highlight acts as a way of illustrating press state. + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); + QVERIFY(firstItem->hasActiveFocus()); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); + QVERIFY(menu->isVisible()); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); + QCOMPARE(clickedSpy.count(), 1); + QCOMPARE(triggeredSpy.count(), 1); + QCOMPARE(visibleSpy.count(), 1); + QVERIFY(!menu->isVisible()); + QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); + + menu->open(); + QCOMPARE(visibleSpy.count(), 2); + QVERIFY(menu->isVisible()); + QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + + // Ensure that we have enough space to click outside of the menu. + QVERIFY(window->width() > menu->contentItem()->width()); + QVERIFY(window->height() > menu->contentItem()->height()); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + QPoint(menu->contentItem()->width() + 1, menu->contentItem()->height() + 1)); + QCOMPARE(visibleSpy.count(), 3); + QVERIFY(!menu->isVisible()); + QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + + menu->open(); + QCOMPARE(visibleSpy.count(), 4); + QVERIFY(menu->isVisible()); + QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + + // Try pressing within the menu and releasing outside of it; it should close. + // TODO: won't work until QQuickPopup::releasedOutside() actually gets emitted +// QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); +// QVERIFY(firstItem->hasActiveFocus()); +// QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); +// QVERIFY(menu->isVisible()); +// QCOMPARE(triggeredSpy.count(), 1); + +// QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(menu->contentItem()->width() + 1, firstItem->height() / 2)); +// QCOMPARE(clickedSpy.count(), 1); +// QCOMPARE(triggeredSpy.count(), 1); +// QCOMPARE(visibleSpy.count(), 5); +// QVERIFY(!menu->isVisible()); +// QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); +// QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); +} + +void tst_QQuickMenu::pressAndHold() +{ + QQuickApplicationHelper helper(this, QLatin1String("pressAndHold.qml")); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QTRY_VERIFY(menu->isVisible()); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QVERIFY(menu->isVisible()); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QTRY_VERIFY(!menu->isVisible()); +} + +void tst_QQuickMenu::contextMenuKeyboard() +{ + if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls) + QSKIP("This platform only allows tab focus for text controls"); + + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QQuickMenu *menu = window->property("menu").value(); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); + + QQuickMenuItem *firstItem = qobject_cast(menu->itemAt(0)); + QVERIFY(firstItem); + QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged())); + + menu->setFocus(true); + menu->open(); + QCOMPARE(visibleSpy.count(), 1); + QVERIFY(menu->isVisible()); + QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QVERIFY(!firstItem->hasActiveFocus()); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); + + QTest::keyClick(window, Qt::Key_Tab); + QVERIFY(firstItem->hasActiveFocus()); + QVERIFY(firstItem->hasVisualFocus()); + QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); + + QQuickMenuItem *secondItem = qobject_cast(menu->itemAt(1)); + QVERIFY(secondItem); + QTest::keyClick(window, Qt::Key_Tab); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(secondItem->hasActiveFocus()); + QVERIFY(secondItem->hasVisualFocus()); + QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1)); + + QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered())); + QTest::keyClick(window, Qt::Key_Space); + QCOMPARE(secondTriggeredSpy.count(), 1); + QCOMPARE(visibleSpy.count(), 2); + QVERIFY(!menu->isVisible()); + QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->hasVisualFocus()); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); + + menu->open(); + QCOMPARE(visibleSpy.count(), 3); + QVERIFY(menu->isVisible()); + QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->hasVisualFocus()); + QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); + + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(firstItem->hasActiveFocus()); + QVERIFY(firstItem->hasVisualFocus()); + QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(secondItem->hasActiveFocus()); + QVERIFY(secondItem->hasVisualFocus()); + QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Down); + QQuickMenuItem *thirdItem = qobject_cast(menu->itemAt(2)); + QVERIFY(thirdItem); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(thirdItem->hasActiveFocus()); + QVERIFY(thirdItem->hasVisualFocus()); + QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason); + + // Key navigation shouldn't wrap by default. + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(thirdItem->hasActiveFocus()); + QVERIFY(thirdItem->hasVisualFocus()); + QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Up); + QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(secondItem->hasActiveFocus()); + QVERIFY(secondItem->hasVisualFocus()); + QCOMPARE(secondItem->focusReason(), Qt::BacktabFocusReason); + QVERIFY(!thirdItem->hasActiveFocus()); + QVERIFY(!thirdItem->hasVisualFocus()); + + QTest::keyClick(window, Qt::Key_Backtab); + QVERIFY(firstItem->hasActiveFocus()); + QVERIFY(firstItem->hasVisualFocus()); + QCOMPARE(firstItem->focusReason(), Qt::BacktabFocusReason); + QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!thirdItem->hasActiveFocus()); + QVERIFY(!thirdItem->hasVisualFocus()); + + QTest::keyClick(window, Qt::Key_Escape); + QCOMPARE(visibleSpy.count(), 4); + QVERIFY(!menu->isVisible()); +} + +void tst_QQuickMenu::menuButton() +{ + if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls) + QSKIP("This platform only allows tab focus for text controls"); + + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QQuickMenu *menu = window->property("menu").value(); + QQuickButton *menuButton = window->property("menuButton").value(); + QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged())); + + menuButton->setVisible(true); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + menuButton->mapToScene(QPointF(menuButton->width() / 2, menuButton->height() / 2)).toPoint()); + QCOMPARE(visibleSpy.count(), 1); + QVERIFY(menu->isVisible()); + + QTest::keyClick(window, Qt::Key_Tab); + QQuickItem *firstItem = menu->itemAt(0); + QVERIFY(firstItem->hasActiveFocus()); +} + +void tst_QQuickMenu::addItem() +{ + QQuickApplicationHelper helper(this, QLatin1String("addItem.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + QQuickItem *menuItem = menu->itemAt(0); + QVERIFY(menuItem); + QTRY_VERIFY(!QQuickItemPrivate::get(menuItem)->culled); // QTBUG-53262 + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + menuItem->mapToScene(QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint()); + QTRY_VERIFY(!menu->isVisible()); +} + +void tst_QQuickMenu::menuSeparator() +{ + QQuickApplicationHelper helper(this, QLatin1String("menuSeparator.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + QQuickMenuItem *newMenuItem = qobject_cast(menu->itemAt(0)); + QVERIFY(newMenuItem); + QCOMPARE(newMenuItem->text(), QStringLiteral("New")); + + QQuickMenuSeparator *menuSeparator = qobject_cast(menu->itemAt(1)); + QVERIFY(menuSeparator); + + QQuickMenuItem *saveMenuItem = qobject_cast(menu->itemAt(2)); + QVERIFY(saveMenuItem); + QCOMPARE(saveMenuItem->text(), QStringLiteral("Save")); + QTRY_VERIFY(!QQuickItemPrivate::get(saveMenuItem)->culled); // QTBUG-53262 + + // Clicking on items should still close the menu. + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + newMenuItem->mapToScene(QPointF(newMenuItem->width() / 2, newMenuItem->height() / 2)).toPoint()); + QTRY_VERIFY(!menu->isVisible()); + + menu->open(); + QVERIFY(menu->isVisible()); + + // Clicking on a separator shouldn't close the menu. + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + menuSeparator->mapToScene(QPointF(menuSeparator->width() / 2, menuSeparator->height() / 2)).toPoint()); + QVERIFY(menu->isVisible()); + + // Clicking on items should still close the menu. + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + saveMenuItem->mapToScene(QPointF(saveMenuItem->width() / 2, saveMenuItem->height() / 2)).toPoint()); + QTRY_VERIFY(!menu->isVisible()); + + menu->open(); + QVERIFY(menu->isVisible()); + + // Key navigation skips separators + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(newMenuItem->hasActiveFocus()); + QVERIFY(newMenuItem->hasVisualFocus()); + QCOMPARE(newMenuItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(saveMenuItem->hasActiveFocus()); + QVERIFY(saveMenuItem->hasVisualFocus()); + QCOMPARE(saveMenuItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(saveMenuItem->hasActiveFocus()); + QVERIFY(saveMenuItem->hasVisualFocus()); + QCOMPARE(saveMenuItem->focusReason(), Qt::TabFocusReason); + + QTest::keyClick(window, Qt::Key_Up); + QVERIFY(newMenuItem->hasActiveFocus()); + QVERIFY(newMenuItem->hasVisualFocus()); + QCOMPARE(newMenuItem->focusReason(), Qt::BacktabFocusReason); + + QTest::keyClick(window, Qt::Key_Up); + QVERIFY(newMenuItem->hasActiveFocus()); + QVERIFY(newMenuItem->hasVisualFocus()); + QCOMPARE(newMenuItem->focusReason(), Qt::BacktabFocusReason); +} + +void tst_QQuickMenu::repeater() +{ + QQuickApplicationHelper helper(this, QLatin1String("repeater.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + QObject *repeater = window->property("repeater").value(); + QVERIFY(repeater); + + int count = repeater->property("count").toInt(); + QCOMPARE(count, 5); + + for (int i = 0; i < count; ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("idx").toInt(), i); + + QQuickItem *repeaterItem = nullptr; + QVERIFY(QMetaObject::invokeMethod(repeater, "itemAt", Q_RETURN_ARG(QQuickItem*, repeaterItem), Q_ARG(int, i))); + QCOMPARE(item, repeaterItem); + } + + repeater->setProperty("model", 3); + + count = repeater->property("count").toInt(); + QCOMPARE(count, 3); + + for (int i = 0; i < count; ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("idx").toInt(), i); + + QQuickItem *repeaterItem = nullptr; + QVERIFY(QMetaObject::invokeMethod(repeater, "itemAt", Q_RETURN_ARG(QQuickItem*, repeaterItem), Q_ARG(int, i))); + QCOMPARE(item, repeaterItem); + } +} + +void tst_QQuickMenu::order() +{ + QQuickApplicationHelper helper(this, QLatin1String("order.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + const QStringList texts = {"dynamic_0", "static_1", "repeated_2", "repeated_3", "static_4", "dynamic_5", "dynamic_6"}; + + for (int i = 0; i < texts.count(); ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("text").toString(), texts.at(i)); + } +} + +QTEST_MAIN(tst_QQuickMenu) + +#include "tst_qquickmenu.moc" -- cgit v1.2.3