diff options
author | Martin Negyokru <[email protected]> | 2025-03-19 14:26:42 +0100 |
---|---|---|
committer | Martin Negyokru <[email protected]> | 2025-06-02 16:28:44 +0200 |
commit | 242b37218c382e2bdc73347c0aff5d6dd68ce9bc (patch) | |
tree | 176ec8b4243e82c91c3a4bf0a89ccaef26a6009e | |
parent | 5b64b4f259ed2dc7b266d2871eafe81c6943aa49 (diff) |
Test QWebEngineExtension and QWebEngineExtenisonManager APIs.
Pick-to: 6.10
Task-number: QTBUG-61676
Change-Id: Ib697bdca2ec1d7f9e86ab9ea88e210dfeb2e1780
Reviewed-by: Allan Sandfeld Jensen <[email protected]>
15 files changed, 487 insertions, 2 deletions
diff --git a/REUSE.toml b/REUSE.toml index 386f0741f..d7733c639 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -54,6 +54,7 @@ path = ["tests/auto/widgets/qwebenginepage/resources/*", "tests/auto/quick/qquickwebenginedefaultsurfaceformat/html/basic_page.html", "tests/auto/quick/qtbug-70248/test.qml", "tests/auto/widgets/defaultsurfaceformat/resources/index.html", + "tests/auto/widgets/extensions/resources/**", "tests/auto/widgets/offscreen/test.html", "tests/auto/widgets/printing/resources/basic_printing_page.html", "tests/auto/widgets/proxypac/proxy.pac", diff --git a/src/core/api/qwebengineextensioninfo.cpp b/src/core/api/qwebengineextensioninfo.cpp index 33af3d3cc..6ea24d658 100644 --- a/src/core/api/qwebengineextensioninfo.cpp +++ b/src/core/api/qwebengineextensioninfo.cpp @@ -5,6 +5,7 @@ #include "qwebengineextensioninfo_p.h" #if QT_CONFIG(webengine_extensions) +#include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> #include "extensions/extension_manager.h" @@ -87,7 +88,7 @@ bool QWebEngineExtensionInfoPrivate::isLoaded() const bool QWebEngineExtensionInfoPrivate::isInstalled() const { - return QFileInfo(m_data.path).path() == m_manager->installDirectory(); + return QFileInfo(m_data.path).dir() == QDir(m_manager->installDirectory()); } QWebEngineExtensionInfo::QWebEngineExtensionInfo() : d_ptr(nullptr) { } diff --git a/src/core/extensions/unpacked_extension_installer.cpp b/src/core/extensions/unpacked_extension_installer.cpp index 9a5eeafdc..fc4a40e63 100644 --- a/src/core/extensions/unpacked_extension_installer.cpp +++ b/src/core/extensions/unpacked_extension_installer.cpp @@ -4,8 +4,58 @@ #include "unpacked_extension_installer.h" #include "base/files/file_util.h" +#include "base/rand_util.h" +#include "base/threading/scoped_blocking_call.h" + +#include <algorithm> +#include <random> namespace QtWebEngineCore { +namespace { +static constexpr const char *kCharSet = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +std::string generateRandomString(size_t length) +{ + std::string str = std::string(kCharSet); + + while (length > str.length()) + str += str; + + auto rng = std::default_random_engine{}; + std::shuffle(str.begin(), str.end(), rng); + return str.substr(0, length); +} + +bool generateDirNameOnFileThread(const base::FilePath &baseDir, + base::FilePath::StringPieceType prefix, base::FilePath *out) +{ + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); + base::FilePath outPath; + + for (int count = 0; count < 50; ++count) { + base::FilePath::StringType newName; + newName.assign(prefix); +#if BUILDFLAG(IS_WIN) + // based on 'CreateTemporaryDirInDir' in chromium/base/file_util_win.cc + newName.append(base::AsWString(base::NumberToString16(base::GetCurrentProcId()))); + newName.push_back('_'); + newName.append(base::AsWString( + base::NumberToString16(base::RandInt(0, std::numeric_limits<int32_t>::max())))); +#else + // based on 'CreateTemporaryDirInDir' in chromium/base/file_util_posix.cc + newName.append(generateRandomString(6)); +#endif + outPath = baseDir.Append(newName); + if (!base::PathExists(outPath)) { + *out = outPath; + return true; + } + } + return false; +} +} // namespace + UnpackedExtensionInstaller::UnpackedExtensionInstaller( const scoped_refptr<base::SequencedTaskRunner> &taskRunner, DoneCallback doneCallback) : m_taskRunner(taskRunner), m_doneCallback(std::move(doneCallback)) @@ -38,7 +88,7 @@ UnpackedExtensionInstaller::installUnpackedExtensionOnFileThread(const base::Fil // mktemp() logic to match the output format of the zip installer. base::FilePath extensionInstallPath; base::FilePath::StringType dirName = src.BaseName().value() + FILE_PATH_LITERAL("_"); - if (!base::CreateTemporaryDirInDir(installDir, dirName, &extensionInstallPath)) { + if (!generateDirNameOnFileThread(installDir, dirName, &extensionInstallPath)) { installInfo.error = "Failed to create install directory for extension"; return installInfo; } diff --git a/tests/auto/widgets/CMakeLists.txt b/tests/auto/widgets/CMakeLists.txt index dbf409385..e31ff2170 100644 --- a/tests/auto/widgets/CMakeLists.txt +++ b/tests/auto/widgets/CMakeLists.txt @@ -31,3 +31,6 @@ endif() if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING AND NOT QT_FEATURE_webengine_native_spellchecker) add_subdirectory(spellchecking) endif() +if(QT_FEATURE_webengine_extensions) + add_subdirectory(extensions) +endif() diff --git a/tests/auto/widgets/extensions/CMakeLists.txt b/tests/auto/widgets/extensions/CMakeLists.txt new file mode 100644 index 000000000..4c99fa623 --- /dev/null +++ b/tests/auto/widgets/extensions/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +include(../../util/util.cmake) + +qt_internal_add_test(tst_qwebengineextension + SOURCES + tst_qwebengineextension.cpp + LIBRARIES + Qt::WebEngineWidgets + Test::Util +) + +set(tst_qwebengineextension_resource_files + "resources/index.html" +) + +qt_internal_add_resource(tst_qwebengineextension "tst_qwebengineextension" + PREFIX + "/" + FILES + ${tst_qwebengineextension_resource_files} +) diff --git a/tests/auto/widgets/extensions/resources/action_popup_ext/manifest.json b/tests/auto/widgets/extensions/resources/action_popup_ext/manifest.json new file mode 100644 index 000000000..ffdba8b14 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/action_popup_ext/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "Extension", + "version": "1.0", + "manifest_version": 3, + "action": { + "default_popup": "popup_page.html" + } +} diff --git a/tests/auto/widgets/extensions/resources/action_popup_ext/popup_page.html b/tests/auto/widgets/extensions/resources/action_popup_ext/popup_page.html new file mode 100644 index 000000000..dfe8c3577 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/action_popup_ext/popup_page.html @@ -0,0 +1,5 @@ +<html> + <body> + Popup page + </body> +</html> diff --git a/tests/auto/widgets/extensions/resources/content_script_ext/manifest.json b/tests/auto/widgets/extensions/resources/content_script_ext/manifest.json new file mode 100644 index 000000000..9c20c27a4 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/content_script_ext/manifest.json @@ -0,0 +1,15 @@ +{ + "name": "content script", + "version": "1.0", + "manifest_version": 3, + "content_scripts": [ + { + "js": [ + "script.js" + ], + "matches": [ + "<all_urls>" + ] + } + ] +} diff --git a/tests/auto/widgets/extensions/resources/content_script_ext/script.js b/tests/auto/widgets/extensions/resources/content_script_ext/script.js new file mode 100644 index 000000000..b7b2abd42 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/content_script_ext/script.js @@ -0,0 +1,4 @@ +let testNode = document.createElement("div") +testNode.innerText = "Hello" +testNode.id = "testNode" +document.body.appendChild(testNode) diff --git a/tests/auto/widgets/extensions/resources/index.html b/tests/auto/widgets/extensions/resources/index.html new file mode 100644 index 000000000..d1d41176c --- /dev/null +++ b/tests/auto/widgets/extensions/resources/index.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<html> + <body> + </body> +</html> diff --git a/tests/auto/widgets/extensions/resources/invalid_manifest_ext/manifest.json b/tests/auto/widgets/extensions/resources/invalid_manifest_ext/manifest.json new file mode 100644 index 000000000..5cb976c79 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/invalid_manifest_ext/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "manifest v2", + "version": "1.0", + "manifest_version": 2 +} diff --git a/tests/auto/widgets/extensions/resources/invalid_manifest_ext_packed.zip b/tests/auto/widgets/extensions/resources/invalid_manifest_ext_packed.zip Binary files differnew file mode 100644 index 000000000..c64866b03 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/invalid_manifest_ext_packed.zip diff --git a/tests/auto/widgets/extensions/resources/packed_ext.zip b/tests/auto/widgets/extensions/resources/packed_ext.zip Binary files differnew file mode 100644 index 000000000..63e0cee23 --- /dev/null +++ b/tests/auto/widgets/extensions/resources/packed_ext.zip diff --git a/tests/auto/widgets/extensions/resources/unpacked_ext/manifest.json b/tests/auto/widgets/extensions/resources/unpacked_ext/manifest.json new file mode 100644 index 000000000..09f8bbace --- /dev/null +++ b/tests/auto/widgets/extensions/resources/unpacked_ext/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "Extension", + "version": "1.0", + "manifest_version": 3 +} diff --git a/tests/auto/widgets/extensions/tst_qwebengineextension.cpp b/tests/auto/widgets/extensions/tst_qwebengineextension.cpp new file mode 100644 index 000000000..0027c95f9 --- /dev/null +++ b/tests/auto/widgets/extensions/tst_qwebengineextension.cpp @@ -0,0 +1,360 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <util.h> +#include <QtTest/QtTest> +#include <QTemporaryDir> +#include <QtWebEngineCore/qwebengineprofile.h> +#include <QtWebEngineCore/qwebenginepage.h> +#include <QtWebEngineCore/qwebenginedownloadrequest.h> +#include <QtWebEngineCore/qwebengineextensionmanager.h> +#include <QtWebEngineCore/qwebengineextensioninfo.h> +#include <QtWebEngineWidgets/qwebengineview.h> +#include <QtWebEngineCore/qwebengineprofilebuilder.h> + +#include <QDir> + +using namespace Qt::StringLiterals; + +class tst_QWebEngineExtension : public QObject +{ + Q_OBJECT + +public Q_SLOTS: + void cleanup(); + void cleanupTestCase(); + void init(); + void initTestCase(); + +private Q_SLOTS: + void installExtension(); + void uninstallExtension(); + void loadExtension(); + void unloadExtension(); + void extensionSetEnabled(); + void reloadExtension(); + void installFailures(); + void uninstallOutsideFromProfileDir(); + void loadFailures(); + void actionPopupUrl(); + void loadInIncognito(); + void installInIncognito(); + void loadInstalledExtensions(); + +private: + int installedFiles(); + int extensionCount(); + QWebEngineExtensionInfo loadExtensionSync(const QString &path); + void unloadExtensionSync(const QWebEngineExtensionInfo &extension); + QWebEngineExtensionInfo installExtensionSync(const QString &path); + void uninstallExtensionSync(const QWebEngineExtensionInfo &extension); + QString resourcesPath(); + QDir extensionsInstallDir(); + + QWebEnginePage *m_page; + QWebEngineProfile *m_profile; + QWebEngineExtensionManager *m_manager; + QString m_resourcesPath; +}; + +int tst_QWebEngineExtension::installedFiles() +{ + return QDir(m_manager->installDirectory()) + .entryInfoList(QDir::AllEntries | QDir::NoDot | QDir::NoDotDot) + .size(); +} + +int tst_QWebEngineExtension::extensionCount() +{ + return m_manager->extensions().size(); +} + +QWebEngineExtensionInfo tst_QWebEngineExtension::loadExtensionSync(const QString &path) +{ + QSignalSpy spy(m_manager, SIGNAL(extensionLoadFinished(QWebEngineExtensionInfo))); + m_manager->loadExtension(path); + spy.wait(); + if (spy.size() != 1) { + qWarning("Did not receive loadFinished signal!"); + return {}; + } + return spy.takeFirst().at(0).value<QWebEngineExtensionInfo>(); +} + +void tst_QWebEngineExtension::unloadExtensionSync(const QWebEngineExtensionInfo &extension) +{ + QSignalSpy spy(m_manager, SIGNAL(extensionUnloadFinished(QWebEngineExtensionInfo))); + m_manager->unloadExtension(extension); + QTRY_COMPARE(spy.size(), 1); +} + +QWebEngineExtensionInfo tst_QWebEngineExtension::installExtensionSync(const QString &path) +{ + QSignalSpy spy(m_manager, SIGNAL(extensionInstallFinished(QWebEngineExtensionInfo))); + m_manager->installExtension(path); + spy.wait(); + if (spy.size() != 1) { + qWarning("Did not receive installFinished signal!"); + return {}; + } + return spy.takeFirst().at(0).value<QWebEngineExtensionInfo>(); +} + +void tst_QWebEngineExtension::uninstallExtensionSync(const QWebEngineExtensionInfo &extension) +{ + QSignalSpy spy(m_manager, SIGNAL(extensionUninstallFinished(QWebEngineExtensionInfo))); + m_manager->uninstallExtension(extension); + QTRY_COMPARE(spy.size(), 1); +} + +QString tst_QWebEngineExtension::resourcesPath() +{ + return m_resourcesPath; +} + +QDir tst_QWebEngineExtension::extensionsInstallDir() +{ + QString path = m_manager->installDirectory(); + return QDir(path); +} + +void tst_QWebEngineExtension::cleanup() +{ + QVERIFY(QDir(m_manager->installDirectory()).removeRecursively()); + QCOMPARE(installedFiles(), 0); + for (auto extension : m_manager->extensions()) + m_manager->unloadExtension(extension); +} + +void tst_QWebEngineExtension::cleanupTestCase() +{ + delete m_page; +} + +void tst_QWebEngineExtension::init() { } + +void tst_QWebEngineExtension::initTestCase() +{ + QTemporaryDir tempDir(QDir::tempPath() + u"tst_QWebEngineExtension-XXXXXX"); + QWebEngineProfileBuilder profileBuilder; + profileBuilder.setPersistentStoragePath(tempDir.path()); + m_profile = profileBuilder.createProfile("Test"); + m_page = new QWebEnginePage(m_profile); + m_manager = m_profile->extensionManager(); + + m_resourcesPath = QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + u"/resources/"_s; +} + +void tst_QWebEngineExtension::installExtension() +{ + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo packedExtension = + installExtensionSync(resourcesPath() + u"packed_ext.zip"); + QVERIFY2(packedExtension.isLoaded(), qPrintable(packedExtension.error())); + QVERIFY2(packedExtension.isInstalled(), qPrintable(packedExtension.error())); + QCOMPARE(installedFiles(), 1); + QCOMPARE(extensionCount(), ++lastExtensionCount); + + QWebEngineExtensionInfo unpackedExtension = + installExtensionSync(resourcesPath() + u"unpacked_ext"); + QVERIFY2(unpackedExtension.isLoaded(), qPrintable(unpackedExtension.error())); + QVERIFY2(unpackedExtension.isInstalled(), qPrintable(unpackedExtension.error())); + QCOMPARE(installedFiles(), 2); + QCOMPARE(extensionCount(), ++lastExtensionCount); +} + +void tst_QWebEngineExtension::uninstallExtension() +{ + QCOMPARE(installedFiles(), 0); + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo packedExtension = + installExtensionSync(resourcesPath() + u"packed_ext.zip"); + uninstallExtensionSync(packedExtension); + QCOMPARE(installedFiles(), 0); + QCOMPARE(extensionCount(), lastExtensionCount); + + QWebEngineExtensionInfo unpackedExtension = + installExtensionSync(resourcesPath() + u"unpacked_ext"); + uninstallExtensionSync(unpackedExtension); + QCOMPARE(installedFiles(), 0); + QCOMPARE(extensionCount(), lastExtensionCount); +} + +void tst_QWebEngineExtension::loadExtension() +{ + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo extension = loadExtensionSync(resourcesPath() + u"unpacked_ext"); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QVERIFY(!extension.isInstalled()); + QCOMPARE(extensionCount(), ++lastExtensionCount); + QCOMPARE(installedFiles(), 0); +} + +void tst_QWebEngineExtension::unloadExtension() +{ + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo extension = loadExtensionSync(resourcesPath() + u"unpacked_ext"); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + unloadExtensionSync(extension); + QCOMPARE(extensionCount(), lastExtensionCount); +} + +void tst_QWebEngineExtension::reloadExtension() +{ + QString path = resourcesPath() + u"unpacked_ext"; + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo extension = loadExtensionSync(path); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QCOMPARE(extensionCount(), ++lastExtensionCount); + extension = loadExtensionSync(path); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + // Loading from the same path acts as a reload + QCOMPARE(extensionCount(), lastExtensionCount); +} + +void tst_QWebEngineExtension::extensionSetEnabled() +{ + QString contentScript = resourcesPath() + u"content_script_ext"; + QWebEngineExtensionInfo extension = loadExtensionSync(contentScript); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QVERIFY(!extension.isEnabled()); + + QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool))); + m_page->load(QUrl("qrc:///resources/index.html")); + QTRY_COMPARE(loadSpy.size(), 1); + QCOMPARE(evaluateJavaScriptSync(m_page, "document.body.childElementCount"), 0); + m_manager->setExtensionEnabled(extension, true); + QVERIFY(extension.isEnabled()); + m_page->triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.size(), 2); + QCOMPARE(evaluateJavaScriptSync(m_page, "document.body.childElementCount"), 1); + + m_manager->setExtensionEnabled(extension, false); + QVERIFY(!extension.isEnabled()); + m_page->triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.size(), 3); + QCOMPARE(evaluateJavaScriptSync(m_page, "document.body.childElementCount"), 0); +} + +void tst_QWebEngineExtension::installFailures() +{ + QCOMPARE(installedFiles(), 0); + QWebEngineExtensionInfo extension = + installExtensionSync(resourcesPath() + u"invalid_manifest_packed.zip"); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QTRY_COMPARE(installedFiles(), 0); + + extension = installExtensionSync(u"invalid_path"_s); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QTRY_COMPARE(installedFiles(), 0); + + extension = installExtensionSync(resourcesPath() + u"non_existent.zip"); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QTRY_COMPARE(installedFiles(), 0); + + extension = installExtensionSync(resourcesPath() + u"invalid_manifest_ext"); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QTRY_COMPARE(installedFiles(), 0); +} + +void tst_QWebEngineExtension::uninstallOutsideFromProfileDir() +{ + QString path = resourcesPath() + u"unpacked_ext"; + QVERIFY(QDir(path).exists()); + QWebEngineExtensionInfo extension = loadExtensionSync(path); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QVERIFY(extension.error().isEmpty()); + QObject::connect( + m_manager, &QWebEngineExtensionManager::extensionUninstallFinished, + [](QWebEngineExtensionInfo extension) { QVERIFY(!extension.error().isEmpty()); }); + uninstallExtensionSync(extension); + QVERIFY(QDir(path).exists()); +} + +void tst_QWebEngineExtension::loadFailures() +{ + int lastExtensionCount = extensionCount(); + QWebEngineExtensionInfo extension = loadExtensionSync(u"invalid_path"_s); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QCOMPARE(extensionCount(), lastExtensionCount); + + extension = loadExtensionSync(resourcesPath()); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QCOMPARE(extensionCount(), lastExtensionCount); + + extension = loadExtensionSync(resourcesPath() + u"invalud_manifest"); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); + QCOMPARE(extensionCount(), lastExtensionCount); +} + +void tst_QWebEngineExtension::actionPopupUrl() +{ + QWebEngineExtensionInfo extension = loadExtensionSync(resourcesPath() + u"unpacked_ext"); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QVERIFY(extension.actionPopupUrl().isEmpty()); + + extension = loadExtensionSync(resourcesPath() + u"action_popup_ext"); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + QVERIFY(!extension.actionPopupUrl().isEmpty()); +} + +void tst_QWebEngineExtension::loadInIncognito() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QWebEngineExtensionManager *manager = profile.extensionManager(); + QSignalSpy spy(manager, SIGNAL(extensionLoadFinished(QWebEngineExtensionInfo))); + manager->loadExtension(resourcesPath() + u"content_script_ext"); + QTRY_COMPARE(spy.size(), 1); + auto extension = spy.takeFirst().at(0).value<QWebEngineExtensionInfo>(); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.error().isEmpty()); +} + +void tst_QWebEngineExtension::installInIncognito() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QWebEngineExtensionManager *manager = profile.extensionManager(); + QSignalSpy spy(manager, SIGNAL(extensionInstallFinished(QWebEngineExtensionInfo))); + manager->installExtension(resourcesPath() + u"packed_ext.zip"); + QTRY_COMPARE(spy.size(), 1); + auto extension = spy.takeFirst().at(0).value<QWebEngineExtensionInfo>(); + QVERIFY(!extension.isLoaded()); + QVERIFY(!extension.isInstalled()); + QVERIFY(!extension.error().isEmpty()); +} + +void tst_QWebEngineExtension::loadInstalledExtensions() +{ + QTemporaryDir tempDir; + QWebEngineProfileBuilder profileBuilder; + profileBuilder.setPersistentStoragePath(tempDir.path()); + QWebEngineProfile *profile = profileBuilder.createProfile("Test"); + QWebEngineExtensionManager *manager = profile->extensionManager(); + + QSignalSpy spy(manager, SIGNAL(extensionInstallFinished(QWebEngineExtensionInfo))); + manager->installExtension(resourcesPath() + u"packed_ext.zip"); + QTRY_COMPARE(spy.size(), 1); + auto extension = spy.takeFirst().at(0).value<QWebEngineExtensionInfo>(); + QVERIFY2(extension.isLoaded(), qPrintable(extension.error())); + + int extensionCount = manager->extensions().size(); + + // recreate the profile to verify installed extensions are loaded at start + delete profile; + profile = profileBuilder.createProfile("Test"); + auto manager2 = profile->extensionManager(); + QTRY_COMPARE(manager2->extensions().size(), extensionCount); +} + +QTEST_MAIN(tst_QWebEngineExtension) +#include "tst_qwebengineextension.moc" |