Skip to content
Merged
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
1 change: 1 addition & 0 deletions qml/components/pickers/DateRangeHeaderFilter.qml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Item {
property bool isFiltered: presetId !== -1
property bool suppressSignal: false
property bool showClearButton: true
property alias presetSelector: inlinePresetSelector

signal dateRangeChanged(int presetId, string startDate, string endDate, string presetLabel)

Expand Down
1 change: 1 addition & 0 deletions qml/components/pickers/DateRangeSelector.qml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Item {
implicitHeight: layout.implicitHeight
height: layout.implicitHeight
property alias labelText: presetSelector.labelText
property alias presetSelector: presetSelector
property date startDate: new Date()
property date endDate: new Date()
signal rangeChanged(date start, date end)
Expand Down
1 change: 1 addition & 0 deletions qml/components/pickers/DaySelector.qml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Item {
property date customDate: selectedDate
property bool showTomorrow: false
property bool readOnly: false
property alias dayCombo: dayCombo
signal dateChanged(date selectedDate)

function formattedDate() {
Expand Down
15 changes: 13 additions & 2 deletions tests/qml/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,36 @@ 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_assigneefiltermenu.qml # Test suite for AssigneeFilterMenu multi-selection, search, and delegate interaction
│ ├── tst_colorpicker.qml # Test suite for ColorPicker palette and custom color
│ ├── tst_contentpickerdialog.qml # Test suite for ContentPickerDialog single/multi selection
│ ├── tst_assigneefiltermenu.qml # Test suite for AssigneeFilterMenu selector component
│ ├── 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_filterableheadercontents.qml # Test suite for FilterableHeaderContents filter state integration
│ ├── tst_globaltimerwidget.qml # Test suite for GlobalTimerWidget system component
│ ├── 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_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_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
│ ├── tst_stagefiltermenu.qml # Test suite for StageFilterMenu stage filter menu toggling
│ ├── tst_statusselector.qml # Test suite for StatusSelector status changes and badge color
│ ├── tst_timepickerpopup.qml # Test suite for TimePickerPopup time selection and confirmation
│ ├── tst_tsbutton.qml # Test suite for TSButton action button component
│ ├── tst_tsiconbutton.qml # Test suite for TSIconButton circular icon button component
│ ├── tst_tslabel.qml # Test suite for TSLabel styled text component
│ ├── 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_tsswitch.qml # Test suite for TSSwitch toggle switch component
│ └── 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`.
Expand Down
37 changes: 37 additions & 0 deletions tests/qml/tst_assigneefiltermenu.qml
Comment thread
suraj-yadav0 marked this conversation as resolved.
Comment thread
suraj-yadav0 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,43 @@ Item {
compare(testMenu.selectedAssigneeIds.length, 0);
}

function test_expandedToggle() {
testMenu.expanded = true;
compare(testMenu.expanded, true);

testMenu.expanded = false;
compare(testMenu.expanded, false);
}

function test_createSelectionAndIsAssigneeSelected() {
var sel = testMenu.createSelection(101, 1);
compare(sel.user_id, 101);
compare(sel.account_id, 1);

testMenu.selectedAssigneeIds = [sel];
verify(testMenu.isAssigneeSelected(101, 1));
verify(!testMenu.isAssigneeSelected(101, 2));
verify(!testMenu.isAssigneeSelected(102, 1));
}

function test_displayAssigneeCacheAndCounts() {
testMenu.assigneeModel = [
{ id: 101, name: "Alice", account_id: 1, email: "alice@example.com" },
{ id: 102, name: "Bob", account_id: 1, email: "bob@example.com" },
{ id: 103, name: "Charlie", account_id: 1, email: "charlie@example.com" }
];
compare(testMenu.getDisplayAssigneeCount(), 3);
compare(testMenu.getSelectedDisplayAssigneeCount(), 0);

testMenu.addSelectionIfMissing(testMenu.createSelection(101, 1));
testMenu.recomputeDisplayAssigneeCache();
compare(testMenu.getSelectedDisplayAssigneeCount(), 1);

testMenu.addSelectionIfMissing(testMenu.createSelection(102, 1));
testMenu.recomputeDisplayAssigneeCache();
compare(testMenu.getSelectedDisplayAssigneeCount(), 2);
}

function test_showAllUsersOption_initialState() {
testMenu.showAllUsersOption = true;
testMenu.selectedAssigneeIds = [];
Expand Down
121 changes: 121 additions & 0 deletions tests/qml/tst_daterangeheaderfilter.qml
Comment thread
suraj-yadav0 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import QtQuick 2.7
import QtTest 1.0
import Lomiri.Components 1.3
import "../../qml/components/pickers"

MainView {
id: testRoot
width: units.gu(40)
height: units.gu(70)

DateRangeHeaderFilter {
id: testHeaderFilter
width: testRoot.width
}

SignalSpy {
id: dateRangeChangedSpy
target: testHeaderFilter
signalName: "dateRangeChanged"
}

TestCase {
name: "DateRangeHeaderFilterTests"
when: windowShown

function init() {
testHeaderFilter.clearFilter();
testHeaderFilter.showClearButton = true;
dateRangeChangedSpy.clear();
}

function cleanup() {
testHeaderFilter.clearFilter();
dateRangeChangedSpy.clear();
}

function test_initialProperties() {
compare(testHeaderFilter.presetId, -1);
compare(testHeaderFilter.startDate, "");
compare(testHeaderFilter.endDate, "");
compare(testHeaderFilter.isFiltered, false);
compare(testHeaderFilter.presetLabel, "No Filter (All Time)");
compare(testHeaderFilter.showClearButton, true);
compare(dateRangeChangedSpy.count, 0);
}

function test_calculateDatesToday() {
var dates = testHeaderFilter.calculateDates(0); // Today
var todayStr = Qt.formatDate(new Date(), "yyyy-MM-dd");
compare(dates.start, todayStr);
compare(dates.end, todayStr);
}

function test_calculateDatesThisMonth() {
var dates = testHeaderFilter.calculateDates(2); // This Month
var now = new Date();
var expectedMonthPrefix = Qt.formatDate(now, "yyyy-MM");
verify(dates.start.indexOf(expectedMonthPrefix + "-01") === 0);
verify(dates.end.indexOf(expectedMonthPrefix) === 0);
}

function test_calculateDatesThisYear() {
var dates = testHeaderFilter.calculateDates(4); // This Year
var y = new Date().getFullYear();
compare(dates.start, y + "-01-01");
compare(dates.end, y + "-12-31");
}

function test_setFilterStateUpdatesPropertiesAndEmitsSignal() {
testHeaderFilter.setFilterState(1, "2026-10-12", "2026-10-18", "This Week");

compare(testHeaderFilter.presetId, 1);
compare(testHeaderFilter.startDate, "2026-10-12");
compare(testHeaderFilter.endDate, "2026-10-18");
compare(testHeaderFilter.presetLabel, "This Week");
compare(testHeaderFilter.isFiltered, true);

compare(dateRangeChangedSpy.count, 1);
var args = dateRangeChangedSpy.signalArguments[0];
compare(args[0], 1);
compare(args[1], "2026-10-12");
compare(args[2], "2026-10-18");
compare(args[3], "This Week");
}

function test_applyPresetTodayTogglesFilterAndRangeText() {
testHeaderFilter.applyPreset(0, "Today");

compare(testHeaderFilter.isFiltered, true);
compare(testHeaderFilter.presetId, 0);
compare(testHeaderFilter.presetLabel, "Today");
verify(testHeaderFilter.startDate !== "");
verify(testHeaderFilter.endDate !== "");
compare(dateRangeChangedSpy.count, 1);
}

function test_clearFilterResetsActiveFilterAndRangeText() {
testHeaderFilter.applyPreset(0, "Today");
compare(testHeaderFilter.isFiltered, true);
dateRangeChangedSpy.clear();

testHeaderFilter.clearFilter();

compare(testHeaderFilter.isFiltered, false);
compare(testHeaderFilter.presetId, -1);
compare(testHeaderFilter.startDate, "");
compare(testHeaderFilter.endDate, "");
compare(testHeaderFilter.presetLabel, "No Filter (All Time)");
compare(dateRangeChangedSpy.count, 1);
compare(dateRangeChangedSpy.signalArguments[0][0], -1);
}

function test_showClearButtonToggling() {
testHeaderFilter.showClearButton = false;
compare(testHeaderFilter.showClearButton, false);

testHeaderFilter.showClearButton = true;
compare(testHeaderFilter.showClearButton, true);
}
}
}
125 changes: 125 additions & 0 deletions tests/qml/tst_daterangeselector.qml
Comment thread
suraj-yadav0 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import QtQuick 2.7
import QtTest 1.0
import Lomiri.Components 1.3
import "../../qml/components/pickers"

MainView {
id: testRoot
width: units.gu(40)
height: units.gu(70)

DateRangeSelector {
id: testDateRangeSelector
width: testRoot.width
}

SignalSpy {
id: rangeChangedSpy
target: testDateRangeSelector
signalName: "rangeChanged"
}

TestCase {
name: "DateRangeSelectorTests"
when: windowShown

function init() {
testDateRangeSelector.readOnly = false;
rangeChangedSpy.clear();
}

function cleanup() {
testDateRangeSelector.readOnly = false;
rangeChangedSpy.clear();
}

function test_initialProperties() {
verify(testDateRangeSelector.startDate instanceof Date);
verify(testDateRangeSelector.endDate instanceof Date);
compare(testDateRangeSelector.readOnly, false);
compare(testDateRangeSelector.isStartDateValid, true);
compare(testDateRangeSelector.isEndDateValid, true);
verify(testDateRangeSelector.presetSelector !== null);
}

function test_formattedDateStrings() {
var s = new Date(2026, 8, 15); // 2026-09-15
var e = new Date(2026, 8, 20); // 2026-09-20
testDateRangeSelector.setDateRange(s, e);

compare(testDateRangeSelector.formattedStartDate(), "2026-09-15");
compare(testDateRangeSelector.formattedEndDate(), "2026-09-20");
}

function test_setDateRangeWithDateObjects() {
var start = new Date(2026, 5, 1);
var end = new Date(2026, 5, 30);
rangeChangedSpy.clear();

testDateRangeSelector.setDateRange(start, end);

compare(rangeChangedSpy.count, 1);
compare(testDateRangeSelector.isStartDateValid, true);
compare(testDateRangeSelector.isEndDateValid, true);
compare(testDateRangeSelector.startDate.getFullYear(), 2026);
compare(testDateRangeSelector.startDate.getMonth(), 5);
compare(testDateRangeSelector.startDate.getDate(), 1);
compare(testDateRangeSelector.endDate.getDate(), 30);
}

function test_setDateRangeWithStringInputs() {
rangeChangedSpy.clear();
testDateRangeSelector.setDateRange("2026-11-05", "2026-11-25");

compare(rangeChangedSpy.count, 1);
compare(testDateRangeSelector.isStartDateValid, true);
compare(testDateRangeSelector.isEndDateValid, true);
compare(testDateRangeSelector.formattedStartDate(), "2026-11-05");
compare(testDateRangeSelector.formattedEndDate(), "2026-11-25");
}

function test_setDateRangeInvalidBoundsHandling() {
testDateRangeSelector.setDateRange("not-a-date", null);

compare(testDateRangeSelector.isStartDateValid, false);
compare(testDateRangeSelector.isEndDateValid, false);
}

function test_updateDatesPresetToday() {
verify(testDateRangeSelector.presetSelector !== null, "presetSelector alias should be accessible");

testDateRangeSelector.presetSelector.selectedId = 0; // Today
rangeChangedSpy.clear();
testDateRangeSelector.updateDates();

compare(rangeChangedSpy.count, 1);
compare(testDateRangeSelector.isStartDateValid, true);
compare(testDateRangeSelector.isEndDateValid, true);
var today = new Date();
compare(testDateRangeSelector.startDate.getDate(), today.getDate());
compare(testDateRangeSelector.endDate.getDate(), today.getDate());
}

function test_updateDatesPresetThisMonth() {
verify(testDateRangeSelector.presetSelector !== null, "presetSelector alias should be accessible");

testDateRangeSelector.presetSelector.selectedId = 3; // This Month
rangeChangedSpy.clear();
testDateRangeSelector.updateDates();

compare(rangeChangedSpy.count, 1);
var today = new Date();
compare(testDateRangeSelector.startDate.getMonth(), today.getMonth());
compare(testDateRangeSelector.endDate.getMonth(), today.getMonth());
verify(testDateRangeSelector.endDate.getDate() >= 26);
}

function test_readOnlyStateToggling() {
testDateRangeSelector.readOnly = true;
compare(testDateRangeSelector.readOnly, true);

testDateRangeSelector.readOnly = false;
compare(testDateRangeSelector.readOnly, false);
}
}
}
Loading
Loading