blob: 801e2a76c77e72c7f53cdac3d2de32ed304779d4 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "util.h"
#include <QtTest/QtTest>
#include <QtWebEngineWidgets/qwebenginecontextmenudata.h>
#include <QtWebEngineWidgets/qwebengineprofile.h>
#include <QtWebEngineWidgets/qwebenginepage.h>
#include <QtWebEngineWidgets/qwebengineview.h>
#include <qwebenginesettings.h>
class WebView : public QWebEngineView
{
Q_OBJECT
public:
void activateMenu(QWidget *widget, const QPoint &position)
{
QTest::mouseMove(widget, position);
QTest::mousePress(widget, Qt::RightButton, {}, position);
QContextMenuEvent evcont(QContextMenuEvent::Mouse, position, mapToGlobal(position));
event(&evcont);
QTest::mouseRelease(widget, Qt::RightButton, {}, position);
}
const QWebEngineContextMenuData& data()
{
return m_data;
}
signals:
void menuReady();
protected:
void contextMenuEvent(QContextMenuEvent *)
{
m_data = page()->contextMenuData();
emit menuReady();
}
private:
QWebEngineContextMenuData m_data;
};
class tst_Spellchecking : public QObject
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void settings();
void spellcheck();
void spellcheck_data();
private:
void load();
WebView *m_view;
};
void tst_Spellchecking::init()
{
m_view = new WebView();
}
void tst_Spellchecking::load()
{
m_view->page()->load(QUrl("qrc:///resources/index.html"));
m_view->show();
QSignalSpy spyFinished(m_view->page(), &QWebEnginePage::loadFinished);
QVERIFY(spyFinished.wait());
}
void tst_Spellchecking::cleanup()
{
delete m_view;
}
void tst_Spellchecking::settings()
{
// Default profile has spellchecking disabled
QVERIFY(!QWebEngineProfile::defaultProfile()->isSpellCheckEnabled());
QVERIFY(QWebEngineProfile::defaultProfile()->spellCheckLanguages().isEmpty());
// New named profiles have spellchecking disabled
auto profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
QVERIFY(!profile1->isSpellCheckEnabled());
QVERIFY(profile1->spellCheckLanguages().isEmpty());
auto profile2 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile2"));
QVERIFY(!profile2->isSpellCheckEnabled());
QVERIFY(profile2->spellCheckLanguages().isEmpty());
// New otr profiles have spellchecking disabled
auto profile3 = std::make_unique<QWebEngineProfile>();
QVERIFY(!profile2->isSpellCheckEnabled());
QVERIFY(profile2->spellCheckLanguages().isEmpty());
// Settings can be changed
profile1->setSpellCheckEnabled(true);
QVERIFY(profile1->isSpellCheckEnabled());
profile1->setSpellCheckLanguages({"en-US"});
QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US"}));
profile1->setSpellCheckLanguages({"en-US","de-DE"});
QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US","de-DE"}));
// Settings are per profile
QVERIFY(!profile2->isSpellCheckEnabled());
QVERIFY(profile2->spellCheckLanguages().isEmpty());
QVERIFY(!profile3->isSpellCheckEnabled());
QVERIFY(profile3->spellCheckLanguages().isEmpty());
// Settings are not persisted
// TODO(juvaldma): Write from dtor currently usually happens *after* the
// read from the ctor, so this test would pass even if settings were
// persisted. It would start to fail on the second run though.
profile1.reset();
profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
QVERIFY(!profile1->isSpellCheckEnabled());
QVERIFY(profile1->spellCheckLanguages().isEmpty());
}
void tst_Spellchecking::spellcheck()
{
QFETCH(QStringList, languages);
QFETCH(QStringList, suggestions);
m_view->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
QVERIFY(profile);
profile->setSpellCheckLanguages(languages);
profile->setSpellCheckEnabled(true);
load();
QCOMPARE(profile->spellCheckLanguages(), languages);
// make textarea editable
evaluateJavaScriptSync(m_view->page(), "makeEditable();");
// calcuate position of misspelled word
QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lowe Qt ....','lowe');").toList();
QRect rect(list[0].value<int>(),list[1].value<int>(),list[2].value<int>(),list[3].value<int>());
//type text, spellchecker needs time
QTest::mouseMove(m_view->focusWidget(), QPoint(20,20));
QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20));
QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20));
QString text("I lowe Qt ....");
for (int i = 0; i < text.length(); i++) {
QTest::keyClicks(m_view->focusWidget(), text.at(i));
QTest::qWait(60);
}
// make sure text is there
QString result = evaluateJavaScriptSync(m_view->page(), "text();").toString();
QVERIFY(result == text);
bool gotMisspelledWord = false; // clumsy QTRY_VERIFY still execs expr after first success
QString detail;
// check that spellchecker has done text processing and filled misspelled word
QTRY_VERIFY2([&] () {
detail.clear();
if (gotMisspelledWord)
return true;
// open menu on misspelled word
m_view->activateMenu(m_view->focusWidget(), rect.center());
QSignalSpy spyMenuReady(m_view, &WebView::menuReady);
if (!spyMenuReady.wait()) {
detail = "menu was not shown";
return false;
}
if (!m_view->data().isValid()) {
detail = "invalid data";
return false;
}
if (!m_view->data().isContentEditable()) {
detail = "content is not editable";
return false;
}
if (m_view->data().misspelledWord().isEmpty()) {
detail = "no misspelled word";
return false;
};
gotMisspelledWord = true;
return true;
} (), qPrintable(QString("Context menu: %1").arg(detail)));
// check misspelled word
QCOMPARE(m_view->data().misspelledWord(), QStringLiteral("lowe"));
// check suggestions
QCOMPARE(m_view->data().spellCheckerSuggestions(), suggestions);
// check replace word
m_view->page()->replaceMisspelledWord("love");
text = "I love Qt ....";
QTRY_VERIFY(evaluateJavaScriptSync(m_view->page(), "text();").toString() == text);
}
void tst_Spellchecking::spellcheck_data()
{
QTest::addColumn<QStringList>("languages");
QTest::addColumn<QStringList>("suggestions");
QTest::newRow("en-US") << QStringList({"en-US"}) << QStringList({"low", "love"});
QTest::newRow("en-US,de-DE") << QStringList({"en-US", "de-DE"}) << QStringList({"löwe", "low", "love"});
}
QTEST_MAIN(tst_Spellchecking)
#include "tst_spellchecking.moc"