summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Negyokru <[email protected]>2025-03-19 14:26:42 +0100
committerMartin Negyokru <[email protected]>2025-06-02 16:28:44 +0200
commit242b37218c382e2bdc73347c0aff5d6dd68ce9bc (patch)
tree176ec8b4243e82c91c3a4bf0a89ccaef26a6009e
parent5b64b4f259ed2dc7b266d2871eafe81c6943aa49 (diff)
Add auto tests for the extension manager APIHEADdev
Test QWebEngineExtension and QWebEngineExtenisonManager APIs. Pick-to: 6.10 Task-number: QTBUG-61676 Change-Id: Ib697bdca2ec1d7f9e86ab9ea88e210dfeb2e1780 Reviewed-by: Allan Sandfeld Jensen <[email protected]>
-rw-r--r--REUSE.toml1
-rw-r--r--src/core/api/qwebengineextensioninfo.cpp3
-rw-r--r--src/core/extensions/unpacked_extension_installer.cpp52
-rw-r--r--tests/auto/widgets/CMakeLists.txt3
-rw-r--r--tests/auto/widgets/extensions/CMakeLists.txt23
-rw-r--r--tests/auto/widgets/extensions/resources/action_popup_ext/manifest.json8
-rw-r--r--tests/auto/widgets/extensions/resources/action_popup_ext/popup_page.html5
-rw-r--r--tests/auto/widgets/extensions/resources/content_script_ext/manifest.json15
-rw-r--r--tests/auto/widgets/extensions/resources/content_script_ext/script.js4
-rw-r--r--tests/auto/widgets/extensions/resources/index.html5
-rw-r--r--tests/auto/widgets/extensions/resources/invalid_manifest_ext/manifest.json5
-rw-r--r--tests/auto/widgets/extensions/resources/invalid_manifest_ext_packed.zipbin0 -> 229 bytes
-rw-r--r--tests/auto/widgets/extensions/resources/packed_ext.zipbin0 -> 230 bytes
-rw-r--r--tests/auto/widgets/extensions/resources/unpacked_ext/manifest.json5
-rw-r--r--tests/auto/widgets/extensions/tst_qwebengineextension.cpp360
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
new file mode 100644
index 000000000..c64866b03
--- /dev/null
+++ b/tests/auto/widgets/extensions/resources/invalid_manifest_ext_packed.zip
Binary files differ
diff --git a/tests/auto/widgets/extensions/resources/packed_ext.zip b/tests/auto/widgets/extensions/resources/packed_ext.zip
new file mode 100644
index 000000000..63e0cee23
--- /dev/null
+++ b/tests/auto/widgets/extensions/resources/packed_ext.zip
Binary files differ
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"