Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions qml/components/visualization/ProjectList.qml
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,17 @@ Item {
function navigateBackInHierarchy() {
if (navigationStackModel.count > 0) {
var last = navigationStackModel.get(navigationStackModel.count - 1);
var prevParentId = (last && last.parentId !== undefined) ? last.parentId : -1;
var prevAccountId = (last && last.accountId !== undefined) ? last.accountId : -1;
var prevParentName = (last && last.parentName !== undefined) ? last.parentName : "";
navigationStackModel.remove(navigationStackModel.count - 1);
currentParentId = last.parentId !== undefined ? last.parentId : -1;
currentParentId = prevParentId;
if (currentParentId === -1) {
currentAccountId = getSelectedAccountId();
} else {
currentAccountId = last.accountId !== undefined ? last.accountId : -1;
currentAccountId = prevAccountId;
}
currentParentName = (last.parentName !== undefined) ? last.parentName : "";
currentParentName = prevParentName;
}
}

Expand Down
13 changes: 8 additions & 5 deletions qml/components/visualization/ProjectPieChart.qml
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ Item {
property var selectedUserId: -1
property bool autoRefreshOnAccountChange: true

property alias chartTitleText: chartTitle.text
property alias series: pieSeries

// Custom styled title overlay
Text {
id: chartTitle
text: i18n.dtr("ubtms", "Most Time-Consuming Projects")
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: units.gu(2)
color: Theme.name === "Ubuntu.Components.Themes.SuruDark" ? "White" : "#444"
color: theme.name === "Ubuntu.Components.Themes.SuruDark" ? "White" : "#444"
padding: units.gu(1.5)
}

Expand Down Expand Up @@ -124,8 +127,8 @@ Item {
y: units.gu(2)
width: Math.min(hoverText.implicitWidth + units.gu(3), parent.width - units.gu(2))
height: hoverText.implicitHeight + units.gu(1.5)
color: Theme.name === "Ubuntu.Components.Themes.SuruDark" ? "#555" : "#FFF"
border.color: Theme.name === "Ubuntu.Components.Themes.SuruDark" ? "#888" : "#ccc"
color: theme.name === "Ubuntu.Components.Themes.SuruDark" ? "#555" : "#FFF"
border.color: theme.name === "Ubuntu.Components.Themes.SuruDark" ? "#888" : "#ccc"
border.width: 1
radius: units.gu(0.5)
opacity: hoverText.text !== "" ? 0.95 : 0.0
Expand All @@ -141,7 +144,7 @@ Item {
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: ""
color: Theme.name === "Ubuntu.Components.Themes.SuruDark" ? "White" : "Black"
color: theme.name === "Ubuntu.Components.Themes.SuruDark" ? "White" : "Black"
font.weight: Font.Light
font.pixelSize: units.gu(2)
}
Expand Down Expand Up @@ -189,7 +192,7 @@ Item {
id: label
text: Utils.truncateText(model.label, 35)
font.pixelSize: units.gu(1.8)
color: Theme.name === "Ubuntu.Components.Themes.SuruDark" ? "white" : "#333"
color: theme.name === "Ubuntu.Components.Themes.SuruDark" ? "white" : "#333"
wrapMode: Text.WordWrap
elide: Text.ElideRight
maximumLineCount: 2
Expand Down
26 changes: 26 additions & 0 deletions tests/qml/QtCharts/ChartView.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import QtQuick 2.7

Item {
id: chartView

default property alias children: contentArea.data

property color backgroundColor: "transparent"
property bool antialiasing: true
property string title: ""

property Margins margins: Margins {}
property Legend legend: Legend {}

property QtObject plotArea: QtObject {
property real x: 0
property real y: 0
property real width: chartView.width
property real height: chartView.height
}

Item {
id: contentArea
anchors.fill: parent
}
}
8 changes: 8 additions & 0 deletions tests/qml/QtCharts/Legend.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import QtQuick 2.7

QtObject {
property bool visible: false
property int alignment: 0
property color labelColor: "black"
property font font
}
8 changes: 8 additions & 0 deletions tests/qml/QtCharts/Margins.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import QtQuick 2.7

QtObject {
property int top: 0
property int bottom: 0
property int left: 0
property int right: 0
}
48 changes: 48 additions & 0 deletions tests/qml/QtCharts/PieSeries.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import QtQuick 2.7

Item {
id: pieSeries
property real size: 0.6
property real holeSize: 0.3
property real horizontalPosition: 0.5
property real verticalPosition: 0.5
property var slices: []
readonly property int count: slices.length

signal hovered(var slice, bool state)

function clear() {
slices = [];
}

function append(label, value) {
var comp = Qt.createComponent("PieSlice.qml");
var startA = 0;
if (slices.length > 0) {
var last = slices[slices.length - 1];
startA = last.startAngle + last.angleSpan;
}

var sliceObj = comp.createObject(pieSeries, {
label: label,
value: value,
startAngle: startA,
angleSpan: 45
});

slices = slices.concat([sliceObj]);
return sliceObj;
}

function at(index) {
if (index >= 0 && index < slices.length) return slices[index];
return null;
}

function find(label) {
for (var i = 0; i < slices.length; i++) {
if (slices[i].label === label) return slices[i];
}
return null;
}
}
22 changes: 22 additions & 0 deletions tests/qml/QtCharts/PieSlice.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import QtQuick 2.7

QtObject {
id: slice

enum LabelPosition {
LabelOutside,
LabelInsideHorizontal,
LabelInsideTangential,
LabelInsideNormal,
LabelArm
}

property string label: ""
property real value: 0
property bool exploded: false
property int labelPosition: 0
property bool labelVisible: false
property color color: "blue"
property real startAngle: 0
property real angleSpan: 0
}
6 changes: 6 additions & 0 deletions tests/qml/QtCharts/qmldir
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module QtCharts
ChartView 2.0 ChartView.qml
PieSeries 2.0 PieSeries.qml
PieSlice 2.0 PieSlice.qml
Margins 2.0 Margins.qml
Legend 2.0 Legend.qml
37 changes: 37 additions & 0 deletions tests/qml/README.md

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QtCharts/ mock directory and the mechanism for mocking modules via -import tests/qml are not documented in the directory structure overview

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ clickable test -- -functions test_openDisplaysMessageAndEmitsSignal
tests/
├── qml/
│ ├── README.md # This guide
│ ├── QtCharts/ # Mock QtCharts module for headless/unit test execution
│ │ ├── qmldir # Module definition registering mock ChartView, PieSeries, etc.
│ │ ├── ChartView.qml # Mock ChartView container component
│ │ ├── Legend.qml # Mock Legend component
│ │ ├── Margins.qml # Mock Margins component
│ │ ├── PieSeries.qml # Mock PieSeries component with slice management
│ │ └── PieSlice.qml # Mock PieSlice component with slice properties
│ ├── models/ # JavaScript core and model test suites
│ │ ├── tst_accounts.qml # Test suite for account management, defaults, sync settings, and deletion
│ │ ├── tst_activity.qml # Test suite for activity data, sanitizeId, type icons, date filters, and CRUD
Expand All @@ -43,23 +50,34 @@ tests/
│ │ ├── tst_squirebridge.qml # Test suite for Squire.js QtWebEngine messaging bridge
│ │ └── tst_taskformutils.qml # Test suite for task form validation and save data preparation
│ ├── tst_accountselectordialog.qml # Test suite for AccountSelectorDialog picker and account switch
│ ├── tst_activitydetailscard.qml # Test suite for ActivityDetailsCard activity details, assignee, due date, and action signals
│ ├── tst_assigneefiltermenu.qml # Test suite for AssigneeFilterMenu multi-selection, search, and delegate interaction
│ ├── tst_attachmentmanager.qml # Test suite for AttachmentManager attachment list, file deletion, and upload signals
│ ├── tst_backendbridge.qml # Test suite for BackendBridge signal dispatch between QML and Python
│ ├── tst_colorpicker.qml # Test suite for ColorPicker palette and custom color
│ ├── tst_contentpickerdialog.qml # Test suite for ContentPickerDialog single/multi selection
│ ├── tst_customdatepicker.qml # Test suite for CustomDatePicker picker component
│ ├── tst_daterangeheaderfilter.qml # Test suite for DateRangeHeaderFilter filter toggle and active range text
│ ├── tst_daterangeselector.qml # Test suite for DateRangeSelector date bounds and range pick
│ ├── tst_dayselector.qml # Test suite for DaySelector day selection signals
│ ├── tst_ehower.qml # Test suite for EHower 2x2 priority matrix layout and quadrant hours
│ ├── tst_ehowerindicator.qml # Test suite for EHowerIndicator quadrant key normalization and quadrant colors
│ ├── tst_filterableheadercontents.qml # Test suite for FilterableHeaderContents filter state integration
│ ├── tst_formdrafthandler.qml # Test suite for FormDraftHandler draft autosave, change tracking, and unsaved changes
│ ├── tst_globaltimerwidget.qml # Test suite for GlobalTimerWidget system component
│ ├── tst_imagepreviewer.qml # Test suite for ImagePreviewer image display, close actions, and download states
│ ├── tst_infobar.qml # Test suite for InfoBar feedback component
│ ├── tst_inlineoptionselector.qml # Test suite for InlineOptionSelector radio-style option selection
│ ├── tst_loadingindicator.qml # Test suite for LoadingIndicator running state and visibility
│ ├── tst_loadmorefooter.qml # Test suite for LoadMoreFooter loading state and retry trigger
│ ├── tst_modeldownloadtimerwidget.qml # Test suite for ModelDownloadTimerWidget download progress and cancel controls
│ ├── tst_multiassigneeselector.qml # Test suite for MultiAssigneeSelector multi-select IDs array output
│ ├── tst_notificationbell.qml # Test suite for NotificationBell unread counter badge and navigation
│ ├── tst_notificationpopup.qml # Test suite for NotificationPopup message, dismiss, and timeout
│ ├── tst_outlinedtextfield.qml # Test suite for OutlinedTextField text input component
│ ├── tst_projectdetailscard.qml # Test suite for ProjectDetailsCard project info, status badge, progress, and timer controls
│ ├── tst_projectlist.qml # Test suite for ProjectList hierarchy navigation stack, list model population, and selection
│ ├── tst_projectpiechart.qml # Test suite for ProjectPieChart pie slice data loading, sorting, and empty state
│ ├── tst_projectstageselector.qml # Test suite for ProjectStageSelector stage list per project
│ ├── tst_savediscarddialog.qml # Test suite for SaveDiscardDialog save, discard, and cancel signals
│ ├── tst_selectionbutton.qml # Test suite for SelectionButton selection state and click
Expand All @@ -72,11 +90,30 @@ tests/
│ ├── tst_tsprogressbar.qml # Test suite for TSProgressbar progress indicator
│ ├── tst_tssearchbar.qml # Test suite for TSSearchBar search input component
│ ├── tst_tsswitch.qml # Test suite for TSSwitch toggle switch component
│ ├── tst_updatesdetailscard.qml # Test suite for UpdatesDetailsCard update summary, timestamp, status, and progress
│ ├── tst_voicetimerwidget.qml # Test suite for VoiceTimerWidget voice recording states and timer controls
│ └── tst_workitemselector.qml # Test suite for WorkItemSelector project and task selection logic
```

Clickable automatically discovers all files matching `tst_*.qml` under `tests/qml/` as configured in `clickable.yaml`.

## Mocking Native Modules via `-import tests/qml`

Components that depend on native or platform modules (such as `QtCharts 2.0`) can be tested headlessly without requiring native C++ Qt plugin binaries or display servers.

In `clickable.yaml`, test execution is configured with:

```bash
test: qmltestrunner -input tests/qml -import tests/qml
```

The `-import tests/qml` option instructs the QML engine's import resolver to look inside `tests/qml/` for QML modules. When a component or test executes `import QtCharts 2.0`, QML finds `tests/qml/QtCharts/qmldir` and resolves `ChartView`, `PieSeries`, `PieSlice`, `Legend`, and `Margins` to the mock QML implementations in `tests/qml/QtCharts/`.

This mechanism allows:
- Testing chart-dependent components (e.g., `ProjectPieChart`, `EHower`) in headless CI/CD environments.
- Simulating slice interactions, hover events, and animations in pure QML without GPU requirements.
- Fast execution and complete isolation from native charting backend state.

## Anatomy of a QML Test Case

Every test file follows this standard template:
Expand Down
Loading
Loading