diff --git a/src/app/ComponentTestWindow.qml b/src/app/ComponentTestWindow.qml
new file mode 100644
index 0000000000000000000000000000000000000000..7729d58634af1a2859ca8b7f65628ec122a106a8
--- /dev/null
+++ b/src/app/ComponentTestWindow.qml
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick
+import QtQuick.Controls
+
+import net.jami.Adapters 1.1
+
+// A window into which we can load a QML file for testing.
+ApplicationWindow {
+    id: appWindow
+    visible: true
+    width: testWidth || loader.implicitWidth || 800
+    height: testHeight || loader.implicitHeight || 600
+    title: testComponentURI
+
+    // WARNING: The following currently must be maintained in tandem with MainApplicationWindow.qml
+    // Used to manage full screen mode and save/restore window geometry.
+    readonly property bool useFrameless: false
+    property bool isRTL: UtilsAdapter.isRTL
+    LayoutMirroring.enabled: isRTL
+    LayoutMirroring.childrenInherit: isRTL
+    property LayoutManager layoutManager: LayoutManager {
+        appContainer: null
+    }
+    // Used to manage dynamic view loading and unloading.
+    property ViewManager viewManager: ViewManager {}
+    // Used to manage the view stack and the current view.
+    property ViewCoordinator viewCoordinator: ViewCoordinator {}
+
+    Loader {
+        id: loader
+        source: Qt.resolvedUrl(testComponentURI)
+        onStatusChanged: {
+            console.log("Status changed to:", loader.status)
+            if (loader.status == Loader.Error || loader.status == Loader.Null) {
+                console.error("Couldn't load component:", source)
+                Qt.exit(1);
+            } else if (loader.status == Loader.Ready) {
+                console.info("Loaded component:", source);
+                // If any of the dimensions are not set, set them to the appWindow's dimensions
+                item.width = item.width || Qt.binding(() => appWindow.width);
+                item.height = item.height || Qt.binding(() => appWindow.height);
+                viewCoordinator.init(item);
+            }
+        }
+    }
+
+    // Closing this window should always exit the application.
+    onClosing: Qt.quit()
+}
diff --git a/src/app/LayoutManager.qml b/src/app/LayoutManager.qml
index f36b2b685f127889d42dff3599716eebafb3771e..97017c2409bb0f84afca8016748bf30823e6810d 100644
--- a/src/app/LayoutManager.qml
+++ b/src/app/LayoutManager.qml
@@ -41,6 +41,20 @@ QtObject {
     // Used to store if a OngoingCallPage component is fullscreened.
     property bool isCallFullscreen: false
 
+    // QWK: Provide spacing for widgets that may be occluded by the system buttons.
+    property QtObject qwkSystemButtonSpacing: QtObject {
+        id: qwkSystemButtonSpacing
+        readonly property bool isMacOS: Qt.platform.os.toString() === "osx"
+        // macOS buttons are on the left.
+        readonly property real left: {
+            appWindow.useFrameless && isMacOS && viewCoordinator.isInSinglePaneMode ? 80 : 0
+        }
+        // Windows and Linux buttons are on the right.
+        readonly property real right: {
+            appWindow.useFrameless && !isMacOS && !root.isFullscreen ? sysBtnsLoader.width + 24 : 0
+        }
+    }
+
     // Restore a visible windowed mode.
     function restoreApp() {
         if (isHidden) {
diff --git a/src/app/MainApplicationWindow.qml b/src/app/MainApplicationWindow.qml
index 31b9dee728b6f1a04cf74f0f8bcc24e6f0c41087..b94475ad25ce1e1f488d04878230d5f2489635bb 100644
--- a/src/app/MainApplicationWindow.qml
+++ b/src/app/MainApplicationWindow.qml
@@ -41,14 +41,11 @@ import QWindowKit
 ApplicationWindow {
     id: appWindow
 
+    readonly property bool useFrameless: UtilsAdapter.getAppValue(Settings.Key.UseFramelessWindow)
     property bool isRTL: UtilsAdapter.isRTL
-
     LayoutMirroring.enabled: isRTL
     LayoutMirroring.childrenInherit: isRTL
 
-    // This needs to be set from the start.
-    readonly property bool useFrameless: UtilsAdapter.getAppValue(Settings.Key.UseFramelessWindow)
-
     onActiveFocusItemChanged: {
         focusOverlay.margin = -5;
         if (activeFocusItem && ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason))) {
@@ -94,16 +91,10 @@ ApplicationWindow {
         id: layoutManager
         appContainer: fullscreenContainer
     }
-
     // Used to manage dynamic view loading and unloading.
-    ViewManager {
-        id: viewManager
-    }
-
+    property ViewManager viewManager: ViewManager {}
     // Used to manage the view stack and the current view.
-    ViewCoordinator {
-        id: viewCoordinator
-    }
+    property ViewCoordinator viewCoordinator: ViewCoordinator {}
 
     // Used to prevent the window from being visible until the
     // window geometry has been restored and the view stack has
@@ -234,17 +225,6 @@ ApplicationWindow {
         anchors.fill: parent
     }
 
-    // QWK: Provide spacing for widgets that may be occluded by the system buttons.
-    QtObject {
-        id: qwkSystemButtonSpacing
-        readonly property bool isMacOS: Qt.platform.os.toString() === "osx"
-        readonly property bool isFullscreen: layoutManager.isFullScreen
-        // macOS buttons are on the left.
-        readonly property real left: useFrameless && isMacOS && viewCoordinator.isInSinglePaneMode ? 80 : 0
-        // Windows and Linux buttons are on the right.
-        readonly property real right: useFrameless && !isMacOS && !isFullscreen ? sysBtnsLoader.width + 24 : 0
-    }
-
     // QWK: Window Title bar
     Item {
         id: titleBar
diff --git a/src/app/mainapplication.cpp b/src/app/mainapplication.cpp
index 48b4fed51bc52a268cdb01f8b98d151c592c7722..8398bbf1b6c2ad56ff129706d315d09195c67b9b 100644
--- a/src/app/mainapplication.cpp
+++ b/src/app/mainapplication.cpp
@@ -335,49 +335,59 @@ MainApplication::parseArguments()
         }
     }
 
-    QCommandLineParser parser;
-    parser.addHelpOption();
-    parser.addVersionOption();
+    parser_.addHelpOption();
+    parser_.addVersionOption();
 
     QCommandLineOption webDebugOption(QStringList() << "remote-debugging-port",
                                       "Web debugging port.",
                                       "port");
-    parser.addOption(webDebugOption);
+    parser_.addOption(webDebugOption);
 
     QCommandLineOption minimizedOption({"m", "minimized"}, "Start minimized.");
-    parser.addOption(minimizedOption);
+    parser_.addOption(minimizedOption);
 
     QCommandLineOption debugOption({"d", "debug"}, "Debug out.");
-    parser.addOption(debugOption);
+    parser_.addOption(debugOption);
 
     QCommandLineOption logFileOption({"f", "file"}, "Debug to <file>.", "file");
-    parser.addOption(logFileOption);
+    parser_.addOption(logFileOption);
 
 #ifdef Q_OS_WINDOWS
     QCommandLineOption updateUrlOption({"u", "url"}, "<url> for debugging version queries.", "url");
-    parser.addOption(updateUrlOption);
+    parser_.addOption(updateUrlOption);
 
 #endif
     QCommandLineOption terminateOption({"t", "term"}, "Terminate all instances.");
-    parser.addOption(terminateOption);
+    parser_.addOption(terminateOption);
 
     QCommandLineOption muteDaemonOption({"q", "quiet"}, "Mute daemon logging. (only if debug)");
-    parser.addOption(muteDaemonOption);
+    parser_.addOption(muteDaemonOption);
 
-    parser.process(*this);
+#ifdef QT_DEBUG
+    // In debug mode, add an option to test a specific QML component via its name.
+    // e.g. ./jami --test AccountComboBox
+    parser_.addOption(QCommandLineOption("test", "Test a QML component via its name.", "uri"));
+    // We may need to force the test window dimensions in the case that the component to test
+    // does not specify its own dimensions and is dependent on parent/sibling dimensions.
+    // e.g. ./jami --test AccountComboBox -w 200
+    parser_.addOption(QCommandLineOption("width", "Width for the test window.", "width"));
+    parser_.addOption(QCommandLineOption("height", "Height for the test window.", "height"));
+#endif
 
-    runOptions_[Option::StartMinimized] = parser.isSet(minimizedOption);
-    runOptions_[Option::Debug] = parser.isSet(debugOption);
-    if (parser.isSet(logFileOption)) {
-        auto logFileValue = parser.value(logFileOption);
+    parser_.process(*this);
+
+    runOptions_[Option::StartMinimized] = parser_.isSet(minimizedOption);
+    runOptions_[Option::Debug] = parser_.isSet(debugOption);
+    if (parser_.isSet(logFileOption)) {
+        auto logFileValue = parser_.value(logFileOption);
         auto logFile = logFileValue.isEmpty() ? Utils::getDebugFilePath() : logFileValue;
         qputenv("JAMI_LOG_FILE", logFile.toStdString().c_str());
     }
 #ifdef Q_OS_WINDOWS
-    runOptions_[Option::UpdateUrl] = parser.value(updateUrlOption);
+    runOptions_[Option::UpdateUrl] = parser_.value(updateUrlOption);
 #endif
-    runOptions_[Option::TerminationRequested] = parser.isSet(terminateOption);
-    runOptions_[Option::MuteDaemon] = parser.isSet(muteDaemonOption);
+    runOptions_[Option::TerminationRequested] = parser_.isSet(terminateOption);
+    runOptions_[Option::MuteDaemon] = parser_.isSet(muteDaemonOption);
 }
 
 void
@@ -393,6 +403,35 @@ MainApplication::setApplicationFont()
     setFont(font);
 }
 
+QString
+findResource(const QString& targetBasename, const QString& basePath = ":/")
+{
+    QDir dir(basePath);
+    // List all entries in the directory excluding special entries '.' and '..'
+    QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
+                                        QDir::DirsFirst);
+
+    Q_FOREACH (const QString& entry, entries) {
+        QString fullPath = basePath + "/" + entry;
+        QFileInfo fileInfo(fullPath);
+
+        if (fileInfo.isDir()) {
+            // Recursively search in subdirectories
+            QString found = findResource(targetBasename, fullPath);
+            if (!found.isEmpty()) {
+                return found; // Return the first match found in any subdirectory
+            }
+        } else if (fileInfo.isFile()
+                   && fileInfo.fileName().contains(targetBasename, Qt::CaseInsensitive)) {
+            // Match found, return the full path but remove the leading ":/".
+            return fileInfo.absoluteFilePath().mid(2);
+        }
+    }
+
+    // No match found in this directory or its subdirectories
+    return QString();
+}
+
 void
 MainApplication::initQmlLayer()
 {
@@ -406,7 +445,30 @@ MainApplication::initQmlLayer()
                          &screenInfo_,
                          this);
 
-    engine_->load(QUrl(QStringLiteral("qrc:/MainApplicationWindow.qml")));
+    QUrl url;
+    if (parser_.isSet("test")) {
+        // List the QML files in the project source tree.
+        const auto targetTestComponent = findResource(parser_.value("test"));
+        if (targetTestComponent.isEmpty()) {
+            C_FATAL << "Failed to find QML component:" << parser_.value("test");
+        }
+        engine_->rootContext()->setContextProperty("testComponentURI", targetTestComponent);
+        // Log the width and height values for the test window.
+        const auto testWidth = parser_.isSet("width") ? parser_.value("width").toInt() : 0;
+        const auto testHeight = parser_.isSet("height") ? parser_.value("height").toInt() : 0;
+        engine_->rootContext()->setContextProperty("testWidth", testWidth);
+        engine_->rootContext()->setContextProperty("testHeight", testHeight);
+        url = u"qrc:/ComponentTestWindow.qml"_qs;
+    } else {
+        url = u"qrc:/MainApplicationWindow.qml"_qs;
+    }
+    QObject::connect(
+        engine_.get(),
+        &QQmlApplicationEngine::objectCreationFailed,
+        this,
+        [url]() { C_FATAL << "Failed to load QML component:" << url; },
+        Qt::QueuedConnection);
+    engine_->load(url);
 
     // Report the render interface used.
     C_DBG << "Main window loaded using" << getRenderInterfaceString();
diff --git a/src/app/mainapplication.h b/src/app/mainapplication.h
index d7117d6870061eadba56827fbb7b73239413f0dc..e318ad73cdf54e63e99902c5da689e90e2d1f3a2 100644
--- a/src/app/mainapplication.h
+++ b/src/app/mainapplication.h
@@ -29,6 +29,7 @@
 #include <QQmlEngine>
 #include <QScreen>
 #include <QWindow>
+#include <QCommandLineParser>
 
 #include <memory>
 
@@ -122,6 +123,6 @@ private:
     SystemTray* systemTray_;
     AppSettingsManager* settingsManager_;
     PreviewEngine* previewEngine_;
-
     ScreenInfo screenInfo_;
+    QCommandLineParser parser_;
 };
diff --git a/src/app/mainview/components/AccountComboBox.qml b/src/app/mainview/components/AccountComboBox.qml
index aa455bd20dd29b3354dc6694a3f2e1dd483f569f..c2f7c3b1c8861e6f0cce8cf9358743a698877371 100644
--- a/src/app/mainview/components/AccountComboBox.qml
+++ b/src/app/mainview/components/AccountComboBox.qml
@@ -29,7 +29,7 @@ Label {
 
     property alias popup: comboBoxPopup
 
-    width: parent ? parent.width : o
+    width: parent ? parent.width : 0
     height: JamiTheme.accountListItemHeight
 
     property bool inSettings: viewCoordinator.currentViewName === "SettingsView"
diff --git a/src/app/mainview/components/ChatViewHeader.qml b/src/app/mainview/components/ChatViewHeader.qml
index d33ab24cc6c72cf6d2ecdc4d0b2f3e26d955f293..69c02d7f77c9c0ed5ed8e6ffaaa6dadcdf83a73c 100644
--- a/src/app/mainview/components/ChatViewHeader.qml
+++ b/src/app/mainview/components/ChatViewHeader.qml
@@ -75,8 +75,8 @@ Rectangle {
 
         anchors.fill: parent
         // QWK: spacing
-        anchors.leftMargin: qwkSystemButtonSpacing.left
-        anchors.rightMargin: 10 + qwkSystemButtonSpacing.right
+        anchors.leftMargin: layoutManager.qwkSystemButtonSpacing.left
+        anchors.rightMargin: 10 + layoutManager.qwkSystemButtonSpacing.right
         spacing: 16
 
         JamiPushButton { QWKSetParentHitTestVisible {}
diff --git a/src/app/mainview/components/MainOverlay.qml b/src/app/mainview/components/MainOverlay.qml
index aabf85e5421c815c2e4437cb213d3ef776758511..455ecb347d5f67be8770bf9cbf9ed04a458a0844 100644
--- a/src/app/mainview/components/MainOverlay.qml
+++ b/src/app/mainview/components/MainOverlay.qml
@@ -131,8 +131,8 @@ Item {
         anchors.left: parent.left
         anchors.right: parent.right
         // QWK: spacing
-        anchors.leftMargin: qwkSystemButtonSpacing.left
-        anchors.rightMargin: qwkSystemButtonSpacing.right
+        anchors.leftMargin: layoutManager.qwkSystemButtonSpacing.left
+        anchors.rightMargin: layoutManager.qwkSystemButtonSpacing.right
 
         RowLayout {
             anchors.fill: parent
diff --git a/tests/qml/src/TestWrapper.qml b/tests/qml/src/TestWrapper.qml
index d8f4510d4b70aef954429bb585d9c826b5ac92d9..0f50f3f8af329f70d12fdabb3509cab034cdec63 100644
--- a/tests/qml/src/TestWrapper.qml
+++ b/tests/qml/src/TestWrapper.qml
@@ -19,6 +19,8 @@ import QtQuick
 import QtQuick.Controls
 import QtTest
 
+import net.jami.Adapters 1.1
+
 import "../../../src/app/"
 
 // The purpose of this component is to fake the ApplicationWindow and prevent
@@ -38,11 +40,23 @@ Item {
 
     Component.onCompleted: viewCoordinator.init(this)
 
-    // These are our fake app management objects. The caveat is that they
-    // must be maintained in sync with the actual objects in the app for now.
-    // The benefit, is that this should be the single place where we need to
-    // sync them.
+    property int visibility: 0
+    Binding {
+        tw.visibility: uut.Window.window.visibility
+        when: QTestRootObject.windowShown
+    }
+
+    // WARNING: The following currently must be maintained in tandem with MainApplicationWindow.qml
+    // Used to manage full screen mode and save/restore window geometry.
+    property bool isRTL: UtilsAdapter.isRTL
+    LayoutMirroring.enabled: isRTL
+    LayoutMirroring.childrenInherit: isRTL
+    property LayoutManager layoutManager: LayoutManager {
+        appContainer: null
+    }
+    // Used to manage dynamic view loading and unloading.
     property ViewManager viewManager: ViewManager {}
+    // Used to manage the view stack and the current view.
     property ViewCoordinator viewCoordinator: ViewCoordinator {}
     property QtObject appWindow: QtObject {
         property bool useFrameless: false