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
30 changes: 23 additions & 7 deletions tests/e2e/default/reports/sidebar-filter.wdio-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,20 +230,23 @@ describe('Reports Sidebar Filter', () => {
expect(await picker.isDisplayed()).to.be.false;

// 4. Select From and To dates
await reportsPage.setSidebarFilterBikFromDate();
await reportsPage.setSidebarFilterBikToDate();
const fromDayText = await reportsPage.setSidebarFilterBikFromDate();
const toDayText = await reportsPage.setSidebarFilterBikToDate();

// Verify both From and To input fields have selected date values
expect(await reportsPage.getFromDateValue()).to.not.equal('');
expect(await reportsPage.getToDateValue()).to.not.equal('');
// Verify both From and To input fields have selected date values and match selection (B9)
const fromDateLabel = await reportsPage.getFromDateValue();
const toDateLabel = await reportsPage.getToDateValue();
expect(fromDateLabel.split(' ')[0]).to.equal(fromDayText);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick (non-blocking): split(' ')[0] keeps the day and discards the month, so a regression that lands on the right day in the wrong month passes silently, which is precisely the #11252 family. The From leg is weaker again, since that helper always picks day १.

expect(toDateLabel.split(' ')[0]).to.equal(toDayText);

// Dismiss the open picker so we can test reopening it
await browser.keys(['Escape']);

// 5. Reopen active selection verification
// 5. Reopen active selection verification (B4)
await reportsPage.clickSidebarFilterToDate();
// Verify that the active selected date is highlighted correctly
// Verify that the active selected date is highlighted correctly and has the correct day text
expect(await reportsPage.isNepaliDatePickerActiveCellDisplayed()).to.be.true;
expect(await reportsPage.getNepaliDatePickerActiveCellText()).to.equal(toDayText);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick (non-blocking): the To helper picks the last enabled cell, which is today, and the picker already marks today active by default. So this assertion would still pass if the reopen-restore logic were removed; what actually makes it fail is an unrelated guard that strips .active when the input is empty. Reopening the From field instead would distinguish "restored the selection" from "defaulted to today".


// Dismiss it
await browser.keys(['Escape']);
Expand All @@ -254,6 +257,19 @@ describe('Reports Sidebar Filter', () => {
expect(await reportsPage.leftPanelSelectors.reportByUUID(pregnancyDistrictHospital._id).isDisplayed()).to.be.true;
expect(await reportsPage.leftPanelSelectors.reportByUUID(visitDistrictHospital._id).isDisplayed()).to.be.true;

// 6. Clear Nepali date filter leg (B11)
const clearDateFilterChip = await reportsPage.sidebarFilterSelectors.clearDateFilterBtn();
await clearDateFilterChip.waitForDisplayed();
await clearDateFilterChip.click();

await commonPage.waitForPageLoaded();

// Verify labels are reset, the filter chip is gone, and the report list goes back to original length
expect(await reportsPage.getFromDateValue()).to.equal('बाट');
expect(await reportsPage.getToDateValue()).to.equal('सम्म');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

issue (blocking): these two expected values are what CI is failing on, 4 attempts out of 4, with expected 'मिति' to equal 'बाट'. Both From and To are the same mm-date-filter component, and date-filter.component.html:10 renders {{ 'Any date' | translate }} whenever inputLabel is falsy, which after a clear it always is. messages-ne.properties:19 defines Any date = मिति, so both fields read मिति once cleared. बाट and सम्म exist in the Nepali bundle only inside two validation-error messages, never as field labels.

Worth knowing for the fix: once both expectations are the same string, these two lines can't tell you which field was cleared. The chip assertion on the next line is the one carrying the weight, since it's driven by the combined fromDateFilter + toDateFilter count.

expect(await reportsPage.sidebarFilterSelectors.dateFilterChip().isExisting()).to.be.false;
expect(await reportsPage.leftPanelSelectors.allReports().length).to.equal(reports.length);

await browser.setCookies({ name: 'locale', value: 'en' });
await browser.refresh();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global window */
const mockConfig = require('../mock-config');

describe('cht-form web component - Bikram Sambat Widget', () => {
Expand Down Expand Up @@ -167,4 +168,39 @@ describe('cht-form web component - Bikram Sambat Widget', () => {
const closeBtn = await picker.$('.close-btn');
await closeBtn.click();
});

it('asserts that a pre-existing date widget is removed', async () => {
const widgets = await $$('.bikram-sambat-widget');
for (const widget of widgets) {
const parent = await widget.parentElement();
const standardDateWidget = await parent.$('.widget.date');
expect(await standardDateWidget.isExisting()).to.be.false;
}
});

it('asserts that the picker renders completely within the viewport', async () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

issue (non-blocking, but B6 shouldn't be ticked): this can't fail for any realistic positioning regression. The enketo widget calls setupNepaliDatePicker without a position (bikram-sambat-datepicker.js:171), and showPickerContainer returns early when position !== 'anchored' (bikram-sambat-picker-shared.js:228), so handleReposition, the only code that keeps the picker inside the viewport, never runs in this harness. The picker is then centred purely by CSS (bikramsambat.less:130-135, position: fixed; top/left: 50%; translate(-50%,-50%)), and a centred element is inside the viewport by construction, so these four assertions reduce to "the picker is not larger than the window". Delete handleReposition entirely and this test stays green.

The behaviour #11246 asks for lives on the anchored path, which only the reports date filter uses (date-filter.component.ts:153), so covering it means exercising that picker, ideally after a scroll so the reposition branch actually runs.

nitpick: also worth noting getLocation() is page-relative while innerWidth/innerHeight are viewport dimensions, so the comparison only holds while the page doesn't scroll. isDisplayedInViewport() avoids mixing the two.

const widgets = await $$('.bikram-sambat-widget');
const firstWidget = widgets[0];
const calBtn = await firstWidget.$('.calendar-btn');
await calBtn.click();

const picker = await $('.nepali-date-picker');
expect(await picker.isDisplayed()).to.be.true;

const viewportSize = await browser.execute(() => ({
width: window.innerWidth,
height: window.innerHeight,
}));
const location = await picker.getLocation();
const size = await picker.getSize();

expect(location.x).to.be.at.least(0);
expect(location.y).to.be.at.least(0);
expect(location.x + size.width).to.be.at.most(viewportSize.width);
expect(location.y + size.height).to.be.at.most(viewportSize.height);

// Close picker
const closeBtn = await picker.$('.close-btn');
await closeBtn.click();
});
});
13 changes: 11 additions & 2 deletions tests/page-objects/default/reports/reports.wdio.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ const sidebarFilterSelectors = {
dateAccordionBody: () => $('#date-filter-accordion mat-panel-description'),
toDate: () => $('#toDateFilter'),
fromDate: () => $('#fromDateFilter'),
dateFilterChip: () => $('#date-filter-accordion mat-expansion-panel-header .chip'),
clearDateFilterBtn: () => $('#date-filter-accordion mat-expansion-panel-header .chip .fa-times'),
formAccordionHeader: () => $('#form-filter-accordion mat-expansion-panel-header'),
formAccordionBody: () => $('#form-filter-accordion mat-panel-description'),
facilityAccordionHeader: () => $('#place-filter-accordion mat-expansion-panel-header'),
Expand Down Expand Up @@ -358,13 +360,19 @@ const setSidebarFilterBikDate = async (fieldPromise, prevClicks, cellIndex) => {
const cells = await picker.$$('table tbody td.current-month-date:not(.disable)');
if (cellIndex === 'last') {
if (cells.length > 0) {
await cells[cells.length - 1].click();
const cell = cells[cells.length - 1];
const text = (await cell.getText()).trim();
await cell.click();
return text;
} else {
throw new Error('No enabled cells found in the Nepali date picker');
}
} else {
if (cells.length > cellIndex) {
await cells[cellIndex].click();
const cell = cells[cellIndex];
const text = (await cell.getText()).trim();
await cell.click();
return text;
} else {
throw new Error(`Requested cell index ${cellIndex} is not available. Only ${cells.length} cells are enabled.`);
}
Expand Down Expand Up @@ -634,4 +642,5 @@ module.exports = {
verifyReport,
openFirstReport,
waitForReportsLoaded,
sidebarFilterSelectors,
};
35 changes: 20 additions & 15 deletions webapp/tests/karma/ts/services/format-date.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,24 +503,29 @@ describe('FormatDate service', () => {
});

it('correctly handles conversion across timezones and negative offsets', () => {
const dateInUTC = moment.utc('2024-06-29T05:00:00Z');
const localDate = dateInUTC.local();

const localDay = localDate.date();
const expectedText = localDay === 29 ? '१५ असार २०८१' : '१४ असार २०८१';
expect(service.date(localDate)).to.equal(expectedText);
// Stub moment.fn.local to return a moment with a fixed -360 (GMT-6) offset
// to ensure a negative offset shift is exercised deterministically
const localStub = sinon.stub(moment.fn, 'local').callsFake(function(this: any) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick (non-blocking): stubbing moment.fn.local patches moment's shared prototype for what is only fixture construction; building the moment at the offset you want avoids touching global state. The test itself is sound and the expected value checks out.

return this.utcOffset(-360);
});
try {
const dateInUTC = moment.utc('2024-06-29T05:00:00Z');
expect(service.date(dateInUTC.local())).to.equal('१४ असार २०८१');
} finally {
localStub.restore();
}
});

it('correctly handles conversion across Daylight Saving Time (DST) boundaries', () => {
const beforeDST = moment('2024-03-10T01:59:59'); // Standard Time
const afterDST = moment('2024-03-10T03:00:00'); // DST (02:00:00 doesn't exist)

expect(service.date(beforeDST)).to.equal('२७ फाल्गुन २०८०');
expect(service.date(afterDST)).to.equal('२७ फाल्गुन २०८०');
});
it('toGreg_text reverse conversion round-trips correctly at month/year boundaries', () => {
const bsYear = 2080;
const bsMonth = 12;
const bsDate = 30;

// Convert BS to Gregorian string: 2080 Chaitra 30 -> 2024-04-12
const gregStr = BikramSambat.toGreg_text(bsYear, bsMonth, bsDate);
expect(gregStr).to.equal('2024-04-12');

it('toGreg_text reverse conversion round-trips correctly at month/year boundaries via the service', () => {
const gregStr = '2024-04-12';
// Convert back to BS using the service and check it matches original values
const formatted = service.date(moment(gregStr));
expect(formatted).to.equal('३० चैत २०८०');
});
Expand Down
Loading