test(e2e): fix recurring task tests failing in CI production builds

Replace window.ng.getComponent() calls with UI-based interactions.
Angular debug APIs are unavailable in production builds (CI uses
ng build which defaults to production config with enableProdMode).

- Use calendar picker instead of signal manipulation for date setting
- Remove page.evaluate() model verification (input value checks suffice)
- Replace waitForTimeout with proper toBeVisible/toBeEnabled waits
- Fix date input focus issues with click + pressSequentially
- Use en-GB date format (DD/MM/YYYY) matching app default locale
This commit is contained in:
Johannes Millan 2026-03-19 11:00:12 +01:00
parent 2431b2748a
commit a578cbfa86
2 changed files with 34 additions and 67 deletions

View file

@ -28,43 +28,42 @@ test.describe('Recurring Task - Future Start Date (#6856)', () => {
// 2. Open task detail and click on recur to open the repeat dialog
await task.hover();
await page.waitForTimeout(200);
const detailBtn = page.getByRole('button', {
name: 'Show/Hide additional info',
});
await expect(detailBtn).toBeVisible({ timeout: 5000 });
await detailBtn.click();
await page.waitForTimeout(300);
const recurItem = page
.locator('task-detail-item')
.filter({ has: page.locator('mat-icon[svgIcon="repeat"]') });
await expect(recurItem).toBeVisible({ timeout: 5000 });
await recurItem.click();
// 3. Wait for the repeat dialog and set a future start date
// 3. Wait for the repeat dialog and set a future start date via calendar
const repeatDialog = page.locator('mat-dialog-container');
await repeatDialog.waitFor({ state: 'visible', timeout: 10000 });
// Set startDate via Angular's dialog component model signal
// (mat-datepicker's signal-based inputs don't work from page.evaluate)
const futureDate = new Date();
futureDate.setMonth(futureDate.getMonth() + 1);
futureDate.setDate(15);
const year = futureDate.getFullYear();
const month = String(futureDate.getMonth() + 1).padStart(2, '0');
const day = String(futureDate.getDate()).padStart(2, '0');
const futureDateStr = `${year}-${month}-${day}`;
// Open the calendar popup
const calendarToggle = repeatDialog.locator('mat-datepicker-toggle button');
await calendarToggle.click();
await page.evaluate((dateStr) => {
const ng = (window as any).ng;
const dialogEl = document.querySelector(
'mat-dialog-container dialog-edit-task-repeat-cfg',
);
if (!ng || !dialogEl) throw new Error('Dialog component not found');
const component = ng.getComponent(dialogEl);
if (!component) throw new Error('Dialog component instance not found');
component.repeatCfg.update((cfg: any) => ({ ...cfg, startDate: dateStr }));
}, futureDateStr);
await page.waitForTimeout(300);
const calendar = page.locator('.mat-calendar');
await expect(calendar).toBeVisible({ timeout: 5000 });
// Navigate to next month to ensure the date is in the future
const nextMonthBtn = page.getByRole('button', { name: /next month/i });
await nextMonthBtn.click();
// Select the first available day in next month
const firstDay = page
.locator('.mat-calendar-body-cell:not(.mat-calendar-body-disabled)')
.first();
await expect(firstDay).toBeVisible({ timeout: 5000 });
await firstDay.click();
// Wait for calendar to close
await expect(calendar).not.toBeVisible({ timeout: 5000 });
// Save the repeat config — wait for the button to be enabled first
const saveBtn = repeatDialog.getByRole('button', { name: /Save/i });
@ -72,16 +71,13 @@ test.describe('Recurring Task - Future Start Date (#6856)', () => {
await saveBtn.click();
await repeatDialog.waitFor({ state: 'hidden', timeout: 10000 });
// 4. Wait for effects and persistence to process
await page.waitForTimeout(5000);
// 5. Reload and navigate to today view to verify persisted state
// 4. Reload and navigate to today view to verify persisted state
await page.reload();
await workViewPage.waitForTaskList();
await page.goto('/#/tag/TODAY/tasks');
await workViewPage.waitForTaskList();
// 6. Assert: task should NOT be visible in today's task list
// 5. Assert: task should NOT be visible in today's task list
// Bug #6856: The task appears immediately instead of being scheduled
// for the configured future start date.
await expect(taskPage.getTaskByText(taskTitle)).not.toBeVisible({ timeout: 5000 });

View file

@ -30,6 +30,7 @@ test.describe('Recurring Task - Start Date Epoch Bug (#6860)', () => {
const detailBtn = page.getByRole('button', {
name: 'Show/Hide additional info',
});
await expect(detailBtn).toBeVisible({ timeout: 5000 });
await detailBtn.click();
const recurItem = page
@ -66,28 +67,9 @@ test.describe('Recurring Task - Start Date Epoch Bug (#6860)', () => {
expect(inputValue).not.toBe('');
expect(inputValue).not.toContain('1970');
// 6. Also verify via the model that it's not epoch
const startDate = await page.evaluate(() => {
const ng = (window as any).ng;
const dialogEl = document.querySelector(
'mat-dialog-container dialog-edit-task-repeat-cfg',
);
if (!ng || !dialogEl) throw new Error('Dialog component not found');
const component = ng.getComponent(dialogEl);
if (!component) throw new Error('Dialog component instance not found');
return component.repeatCfg().startDate;
});
expect(startDate).toBeDefined();
expect(startDate).not.toBe('1970-01-01');
// The date should be in the future (next month)
const today = new Date();
const startDateObj = new Date(startDate + 'T00:00:00');
expect(startDateObj.getTime()).toBeGreaterThan(today.getTime());
// 7. Save and verify the date survives persistence
// 6. Save and verify the date survives persistence
const saveBtn = repeatDialog.getByRole('button', { name: /Save/i });
await expect(saveBtn).toBeEnabled({ timeout: 5000 });
await saveBtn.click();
await repeatDialog.waitFor({ state: 'hidden', timeout: 10000 });
});
@ -112,6 +94,7 @@ test.describe('Recurring Task - Start Date Epoch Bug (#6860)', () => {
const detailBtn = page.getByRole('button', {
name: 'Show/Hide additional info',
});
await expect(detailBtn).toBeVisible({ timeout: 5000 });
await detailBtn.click();
const recurItem = page
@ -128,8 +111,10 @@ test.describe('Recurring Task - Start Date Epoch Bug (#6860)', () => {
// The app defaults to en-GB locale (DD/MM/YYYY format)
const dateInput = repeatDialog.getByRole('textbox', { name: /start date/i });
await expect(dateInput).toBeVisible();
await dateInput.clear();
await dateInput.fill('15/06/2026');
// Click to focus the input, then select all and type the date
await dateInput.click();
await dateInput.press('Control+a');
await dateInput.pressSequentially('15/06/2026', { delay: 50 });
// Trigger change by pressing Tab to blur
await dateInput.press('Tab');
@ -138,23 +123,9 @@ test.describe('Recurring Task - Start Date Epoch Bug (#6860)', () => {
expect(inputValue).not.toBe('');
expect(inputValue).not.toContain('1970');
// 6. Verify via model that the date was preserved
const startDate = await page.evaluate(() => {
const ng = (window as any).ng;
const dialogEl = document.querySelector(
'mat-dialog-container dialog-edit-task-repeat-cfg',
);
if (!ng || !dialogEl) throw new Error('Dialog component not found');
const component = ng.getComponent(dialogEl);
if (!component) throw new Error('Dialog component instance not found');
return component.repeatCfg().startDate;
});
expect(startDate).toBeDefined();
expect(startDate).not.toBe('1970-01-01');
// 7. Save
// 6. Save
const saveBtn = repeatDialog.getByRole('button', { name: /Save/i });
await expect(saveBtn).toBeEnabled({ timeout: 5000 });
await saveBtn.click();
await repeatDialog.waitFor({ state: 'hidden', timeout: 10000 });
});