tests: fix

This commit is contained in:
Johannes Millan 2026-01-21 10:08:26 +01:00
parent e673d74b55
commit 97d59ffcb4
5 changed files with 1009 additions and 5 deletions

View file

@ -0,0 +1,569 @@
import { createScheduleDays } from './create-schedule-days';
import { DEFAULT_TASK, TaskWithoutReminder } from '../../tasks/task.model';
import { PlannerDayMap } from '../../planner/planner.model';
import { BlockedBlockByDayMap } from '../schedule.model';
// Helper function to create test tasks with required properties
const createTestTask = (
id: string,
title: string,
options: {
timeEstimate?: number;
timeSpent?: number;
dueDay?: string;
dueWithTime?: number;
} = {},
): TaskWithoutReminder => {
return {
...DEFAULT_TASK,
id,
title,
projectId: 'test-project',
timeEstimate: options.timeEstimate ?? 3600000,
timeSpent: options.timeSpent ?? 0,
remindAt: undefined,
...(options.dueDay && { dueDay: options.dueDay }),
...(options.dueWithTime && { dueWithTime: options.dueWithTime }),
} as TaskWithoutReminder;
};
describe('createScheduleDays - Task Filtering', () => {
let now: number;
let realNow: number;
let todayStr: string;
let tomorrowStr: string;
let nextWeekStr: string;
let futureWeekStr: string;
beforeEach(() => {
// Set up test dates
const today = new Date(2026, 0, 20, 10, 0, 0); // Jan 20, 2026, 10:00 AM
now = today.getTime();
realNow = now;
todayStr = today.toISOString().split('T')[0];
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrowStr = tomorrow.toISOString().split('T')[0];
const nextWeek = new Date(today);
nextWeek.setDate(nextWeek.getDate() + 7);
nextWeekStr = nextWeek.toISOString().split('T')[0];
const futureWeek = new Date(today);
futureWeek.setDate(futureWeek.getDate() + 14);
futureWeekStr = futureWeek.toISOString().split('T')[0];
});
describe('Unscheduled tasks (no dueDay, no dueWithTime, no plannedForDay)', () => {
it('should appear in current week when viewing today', () => {
// Arrange
const unscheduledTask = createTestTask('task1', 'Unscheduled Task');
const dayDates = [todayStr, tomorrowStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[unscheduledTask],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
// Unscheduled task should appear in the schedule
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task1'),
);
expect(hasTask).toBe(true);
});
it('should NOT appear when viewing next week (outside current week)', () => {
// Arrange
const unscheduledTask: TaskWithoutReminder = {
id: 'task1',
title: 'Unscheduled Task',
timeEstimate: 3600000,
timeSpent: 0,
} as TaskWithoutReminder;
// Viewing a week starting 7 days from now
const dayDates = [nextWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[unscheduledTask],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
// Unscheduled task should NOT appear when viewing future week
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task1'),
);
expect(hasTask).toBe(false);
});
});
describe('Tasks with dueDay', () => {
it('should be filtered out when viewing next week if dueDay is today', () => {
// Arrange
const taskWithDueToday = createTestTask('task2', 'Task Due Today', {
dueDay: todayStr,
});
// Viewing next week
const dayDates = [nextWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskWithDueToday],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task2'),
);
expect(hasTask).toBe(false);
});
it('should appear when viewing a week that includes the dueDay', () => {
// Arrange
const taskDueNextWeek = createTestTask('task3', 'Task Due Next Week', {
dueDay: nextWeekStr,
});
// Viewing next week
const dayDates = [nextWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskDueNextWeek],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task3'),
);
expect(hasTask).toBe(true);
});
it('should appear when dueDay is in the future relative to viewed week', () => {
// Arrange
const taskDueFutureWeek = createTestTask('task4', 'Task Due Future Week', {
dueDay: futureWeekStr,
});
// Viewing next week (before the due date)
const dayDates = [nextWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskDueFutureWeek],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task4'),
);
expect(hasTask).toBe(true);
});
it('should NOT appear when dueDay is before the viewed week', () => {
// Arrange
const taskDueToday = createTestTask('task5', 'Task Due Today', {
dueDay: todayStr,
});
// Viewing future week (2 weeks ahead)
const dayDates = [futureWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskDueToday],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task5'),
);
expect(hasTask).toBe(false);
});
});
describe('Tasks with plannedForDay', () => {
it('should always appear on their planned day regardless of viewing week', () => {
// Arrange
const taskPlannedForNextWeek = createTestTask('task6', 'Task Planned Next Week');
// Planned for next week
const plannerDayMap: PlannerDayMap = {
[nextWeekStr]: [taskPlannedForNextWeek],
};
const dayDates = [nextWeekStr];
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some(
(day) =>
day.dayDate === nextWeekStr &&
day.entries.some((entry) => entry.id === 'task6'),
);
expect(hasTask).toBe(true);
});
it('should appear on planned day even when viewing outside current week', () => {
// Arrange
const taskPlannedForFutureWeek = createTestTask(
'task7',
'Task Planned Future Week',
);
// Planned for future week
const plannerDayMap: PlannerDayMap = {
[futureWeekStr]: [taskPlannedForFutureWeek],
};
const dayDates = [futureWeekStr];
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some(
(day) =>
day.dayDate === futureWeekStr &&
day.entries.some((entry) => entry.id === 'task7'),
);
expect(hasTask).toBe(true);
});
});
describe('Initial filter when first day is outside current week', () => {
it('should filter out unscheduled tasks before processing when first day is outside current week', () => {
// Arrange
const unscheduledTask = createTestTask('task8', 'Unscheduled Task');
const taskWithDueInFuture = createTestTask('task9', 'Task Due Future', {
dueDay: futureWeekStr,
});
// Viewing future week (outside current week)
const dayDates = [futureWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[unscheduledTask, taskWithDueInFuture],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasUnscheduledTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task8'),
);
const hasTaskWithDue = result.some((day) =>
day.entries.some((entry) => entry.id === 'task9'),
);
expect(hasUnscheduledTask).toBe(false);
expect(hasTaskWithDue).toBe(true);
});
it('should keep tasks with plannedForDay even when first day is outside current week', () => {
// Arrange
const taskPlannedForFuture = createTestTask('task10', 'Task Planned for Future');
const plannerDayMap: PlannerDayMap = {
[futureWeekStr]: [taskPlannedForFuture],
};
const dayDates = [futureWeekStr];
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task10'),
);
expect(hasTask).toBe(true);
});
});
describe('Per-day filter for tasks flowing from previous day', () => {
it('should filter tasks between days when viewing outside current week', () => {
// Arrange
const taskDueOnFirstDay = createTestTask('task11', 'Task Due on First Day', {
dueDay: nextWeekStr,
});
// Viewing two days in next week
const secondDayNextWeek = new Date(nextWeekStr);
secondDayNextWeek.setDate(secondDayNextWeek.getDate() + 1);
const secondDayStr = secondDayNextWeek.toISOString().split('T')[0];
const dayDates = [nextWeekStr, secondDayStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskDueOnFirstDay],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
// Task should appear on first day
const firstDayHasTask = result[0].entries.some((entry) => entry.id === 'task11');
expect(firstDayHasTask).toBe(true);
// If task doesn't complete and flows to second day, check if filtering applies
// (This depends on implementation details of budget and beyond budget logic)
});
});
describe('End-of-day filter for tasks flowing to next day', () => {
it('should allow tasks with plannedForDay to flow to next day', () => {
// Arrange
const taskPlannedForToday = createTestTask('task12', 'Task Planned for Today', {
timeEstimate: 86400000, // 24 hours - won't fit in one day
});
const plannerDayMap: PlannerDayMap = {
[todayStr]: [taskPlannedForToday],
};
const dayDates = [todayStr, tomorrowStr];
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
// Task should appear on today
const todayHasTask = result[0].entries.some((entry) => entry.id === 'task12');
expect(todayHasTask).toBe(true);
});
});
describe('Tasks with dueWithTime', () => {
it('should appear when viewing a week that includes the dueWithTime', () => {
// Arrange
const nextWeekDate = new Date(nextWeekStr);
nextWeekDate.setHours(14, 0, 0, 0); // 2 PM next week
const taskWithDueTime = createTestTask('task13', 'Task With Due Time', {
dueWithTime: nextWeekDate.getTime(),
});
const dayDates = [nextWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskWithDueTime],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task13'),
);
expect(hasTask).toBe(true);
});
it('should NOT appear when dueWithTime is before the viewed week', () => {
// Arrange
const todayDate = new Date(todayStr);
todayDate.setHours(14, 0, 0, 0);
const taskWithDueTime = createTestTask('task14', 'Task With Due Time Today', {
dueWithTime: todayDate.getTime(),
});
// Viewing future week
const dayDates = [futureWeekStr];
const plannerDayMap: PlannerDayMap = {};
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[taskWithDueTime],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasTask = result.some((day) =>
day.entries.some((entry) => entry.id === 'task14'),
);
expect(hasTask).toBe(false);
});
});
describe('Mixed scenarios', () => {
it('should correctly filter multiple tasks with different scheduling types when viewing future week', () => {
// Arrange
const unscheduledTask = createTestTask('unscheduled', 'Unscheduled');
const taskDueToday = createTestTask('dueToday', 'Due Today', {
dueDay: todayStr,
});
const taskDueNextWeek = createTestTask('dueNextWeek', 'Due Next Week', {
dueDay: nextWeekStr,
});
const taskPlannedNextWeek = createTestTask('plannedNextWeek', 'Planned Next Week');
const plannerDayMap: PlannerDayMap = {
[nextWeekStr]: [taskPlannedNextWeek],
};
const dayDates = [nextWeekStr];
const blockerBlocksDayMap: BlockedBlockByDayMap = {};
// Act
const result = createScheduleDays(
[unscheduledTask, taskDueToday, taskDueNextWeek],
[],
dayDates,
plannerDayMap,
blockerBlocksDayMap,
undefined,
now,
realNow,
);
// Assert
const hasUnscheduled = result.some((day) =>
day.entries.some((entry) => entry.id === 'unscheduled'),
);
const hasDueToday = result.some((day) =>
day.entries.some((entry) => entry.id === 'dueToday'),
);
const hasDueNextWeek = result.some((day) =>
day.entries.some((entry) => entry.id === 'dueNextWeek'),
);
const hasPlannedNextWeek = result.some((day) =>
day.entries.some((entry) => entry.id === 'plannedNextWeek'),
);
expect(hasUnscheduled).toBe(false);
expect(hasDueToday).toBe(false);
expect(hasDueNextWeek).toBe(true);
expect(hasPlannedNextWeek).toBe(true);
});
});
});

View file

@ -0,0 +1,416 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ScheduleMonthComponent } from './schedule-month.component';
import { ScheduleService } from '../schedule.service';
import { DateTimeFormatService } from '../../../core/date-time-format/date-time-format.service';
describe('ScheduleMonthComponent', () => {
let component: ScheduleMonthComponent;
let fixture: ComponentFixture<ScheduleMonthComponent>;
let mockScheduleService: jasmine.SpyObj<ScheduleService>;
let mockDateTimeFormatService: jasmine.SpyObj<DateTimeFormatService>;
beforeEach(async () => {
mockScheduleService = jasmine.createSpyObj('ScheduleService', [
'getDayClass',
'hasEventsForDay',
'getEventsForDay',
'getEventDayStr',
]);
mockScheduleService.getDayClass.and.returnValue('');
mockScheduleService.hasEventsForDay.and.returnValue(false);
mockScheduleService.getEventsForDay.and.returnValue([]);
mockScheduleService.getEventDayStr.and.returnValue(null);
mockDateTimeFormatService = jasmine.createSpyObj('DateTimeFormatService', ['-'], {
currentLocale: 'en-US',
});
await TestBed.configureTestingModule({
imports: [ScheduleMonthComponent],
providers: [
{ provide: ScheduleService, useValue: mockScheduleService },
{ provide: DateTimeFormatService, useValue: mockDateTimeFormatService },
],
}).compileComponents();
fixture = TestBed.createComponent(ScheduleMonthComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('referenceMonth computed', () => {
it('should return current date when daysToShow is empty', () => {
// Arrange
fixture.componentRef.setInput('daysToShow', []);
fixture.detectChanges();
// Act
const result = component.referenceMonth();
// Assert
expect(result).toBeInstanceOf(Date);
// Should be close to current date
const now = new Date();
expect(Math.abs(result.getTime() - now.getTime())).toBeLessThan(1000);
});
it('should use middle day from daysToShow as reference', () => {
// Arrange - Create a month view for January 2026
const days = [
'2025-12-29', // Week 1 - padding from prev month
'2025-12-30',
'2025-12-31',
'2026-01-01',
'2026-01-02',
'2026-01-03',
'2026-01-04',
'2026-01-05', // Week 2
'2026-01-06',
'2026-01-07',
'2026-01-08',
'2026-01-09',
'2026-01-10',
'2026-01-11',
'2026-01-12', // Week 3 - Middle of month
'2026-01-13',
'2026-01-14', // Day 14 - near middle
'2026-01-15', // Middle index (14/2 = 7, but floor(28/2) = 14)
'2026-01-16',
'2026-01-17',
'2026-01-18',
'2026-01-19', // Week 4
'2026-01-20',
'2026-01-21',
'2026-01-22',
'2026-01-23',
'2026-01-24',
'2026-01-25',
];
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
// Act
const result = component.referenceMonth();
// Assert
// Middle index = floor(28/2) = 14, which is '2026-01-12'
expect(result.getFullYear()).toBe(2026);
expect(result.getMonth()).toBe(0); // January
expect(result.getDate()).toBe(12);
});
it('should handle a 5-week month view', () => {
// Arrange - 35 days (5 weeks)
const days: string[] = [];
const startDate = new Date(2026, 0, 1); // Jan 1, 2026
for (let i = 0; i < 35; i++) {
const date = new Date(startDate);
date.setDate(date.getDate() + i);
days.push(date.toISOString().split('T')[0]);
}
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
// Act
const result = component.referenceMonth();
// Assert
// Middle index = floor(35/2) = 17
const middleDay = new Date(days[17]);
expect(result.getFullYear()).toBe(middleDay.getFullYear());
expect(result.getMonth()).toBe(middleDay.getMonth());
expect(result.getDate()).toBe(middleDay.getDate());
});
it('should handle a 6-week month view', () => {
// Arrange - 42 days (6 weeks)
const days: string[] = [];
const startDate = new Date(2026, 0, 1);
for (let i = 0; i < 42; i++) {
const date = new Date(startDate);
date.setDate(date.getDate() + i);
days.push(date.toISOString().split('T')[0]);
}
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
// Act
const result = component.referenceMonth();
// Assert
// Middle index = floor(42/2) = 21
const middleDay = new Date(days[21]);
expect(result.getFullYear()).toBe(middleDay.getFullYear());
expect(result.getMonth()).toBe(middleDay.getMonth());
});
});
describe('getDayClass', () => {
it('should pass referenceMonth to service.getDayClass', () => {
// Arrange
const days = ['2026-01-15', '2026-01-16', '2026-01-17'];
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
mockScheduleService.getDayClass.calls.reset();
const testDay = '2026-01-15';
// Act
component.getDayClass(testDay);
// Assert
expect(mockScheduleService.getDayClass).toHaveBeenCalled();
const args = mockScheduleService.getDayClass.calls.mostRecent().args;
expect(args[0]).toBe(testDay);
expect(args[1]).toBeInstanceOf(Date);
// Reference month should be the middle day
const referenceMonth = args[1] as Date;
expect(referenceMonth.getFullYear()).toBe(2026);
expect(referenceMonth.getMonth()).toBe(0); // January
});
it('should return the class string from service', () => {
// Arrange
mockScheduleService.getDayClass.and.returnValue('test-class');
const days = ['2026-01-15'];
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
// Act
const result = component.getDayClass('2026-01-15');
// Assert
expect(result).toBe('test-class');
});
it('should handle "other-month" class for padding days', () => {
// Arrange
mockScheduleService.getDayClass.and.callFake((day: string, ref?: Date) => {
const dayDate = new Date(day);
if (ref && dayDate.getMonth() !== ref.getMonth()) {
return 'other-month';
}
return '';
});
const days = [
'2025-12-31', // Previous month
'2026-01-01', // Current month
'2026-02-01', // Next month
];
fixture.componentRef.setInput('daysToShow', days);
fixture.detectChanges();
// Act
const prevMonthClass = component.getDayClass('2025-12-31');
const currentMonthClass = component.getDayClass('2026-01-01');
const nextMonthClass = component.getDayClass('2026-02-01');
// Assert
expect(prevMonthClass).toBe('other-month');
expect(currentMonthClass).toBe('');
expect(nextMonthClass).toBe('other-month');
});
});
describe('getWeekIndex', () => {
it('should return 0 for first week (days 0-6)', () => {
expect(component.getWeekIndex(0)).toBe(0);
expect(component.getWeekIndex(3)).toBe(0);
expect(component.getWeekIndex(6)).toBe(0);
});
it('should return 1 for second week (days 7-13)', () => {
expect(component.getWeekIndex(7)).toBe(1);
expect(component.getWeekIndex(10)).toBe(1);
expect(component.getWeekIndex(13)).toBe(1);
});
it('should return correct week index for later weeks', () => {
expect(component.getWeekIndex(14)).toBe(2);
expect(component.getWeekIndex(21)).toBe(3);
expect(component.getWeekIndex(28)).toBe(4);
expect(component.getWeekIndex(35)).toBe(5);
});
});
describe('getDayIndex', () => {
it('should return 0-6 for days within a week', () => {
expect(component.getDayIndex(0)).toBe(0);
expect(component.getDayIndex(1)).toBe(1);
expect(component.getDayIndex(6)).toBe(6);
expect(component.getDayIndex(7)).toBe(0);
expect(component.getDayIndex(13)).toBe(6);
expect(component.getDayIndex(14)).toBe(0);
});
});
describe('weekdayHeaders computed', () => {
it('should generate 7 weekday headers', () => {
// Arrange
fixture.componentRef.setInput('firstDayOfWeek', 0); // Sunday
fixture.detectChanges();
// Act
const headers = component.weekdayHeaders();
// Assert
expect(headers.length).toBe(7);
});
it('should start with Sunday when firstDayOfWeek is 0', () => {
// Arrange
fixture.componentRef.setInput('firstDayOfWeek', 0);
fixture.detectChanges();
// Act
const headers = component.weekdayHeaders();
// Assert
// Sunday should be first
expect(headers[0]).toContain('Sun');
});
it('should start with Monday when firstDayOfWeek is 1', () => {
// Arrange
fixture.componentRef.setInput('firstDayOfWeek', 1);
fixture.detectChanges();
// Act
const headers = component.weekdayHeaders();
// Assert
// Monday should be first
expect(headers[0]).toContain('Mon');
});
it('should cycle correctly for all days of week', () => {
// Arrange
fixture.componentRef.setInput('firstDayOfWeek', 0); // Sunday
fixture.detectChanges();
// Act
const headers = component.weekdayHeaders();
// Assert
expect(headers.length).toBe(7);
// Should have all unique days
const uniqueHeaders = new Set(headers);
expect(uniqueHeaders.size).toBe(7);
});
});
describe('Service method delegation', () => {
it('should delegate hasEventsForDay to service', () => {
// Arrange
mockScheduleService.hasEventsForDay.and.returnValue(true);
const testDay = '2026-01-15';
const testEvents = [] as any;
fixture.componentRef.setInput('events', testEvents);
fixture.detectChanges();
// Act
const result = component.hasEventsForDay(testDay);
// Assert
expect(mockScheduleService.hasEventsForDay).toHaveBeenCalledWith(
testDay,
testEvents,
);
expect(result).toBe(true);
});
it('should delegate getEventsForDay to service', () => {
// Arrange
const testEvents = [{ id: 'event1' }] as any;
mockScheduleService.getEventsForDay.and.returnValue(testEvents);
const testDay = '2026-01-15';
fixture.componentRef.setInput('events', []);
fixture.detectChanges();
// Act
const result = component.getEventsForDay(testDay);
// Assert
expect(mockScheduleService.getEventsForDay).toHaveBeenCalledWith(testDay, []);
expect(result).toEqual(testEvents);
});
it('should delegate getEventDayStr to service', () => {
// Arrange
const testEvent = { id: 'event1' } as any;
mockScheduleService.getEventDayStr.and.returnValue('2026-01-15');
// Act
const result = component.getEventDayStr(testEvent);
// Assert
expect(mockScheduleService.getEventDayStr).toHaveBeenCalledWith(testEvent);
expect(result).toBe('2026-01-15');
});
});
describe('Input handling', () => {
it('should accept events input', () => {
// Arrange
const testEvents = [{ id: 'event1' }] as any;
// Act
fixture.componentRef.setInput('events', testEvents);
fixture.detectChanges();
// Assert
expect(component.events()).toEqual(testEvents);
});
it('should accept daysToShow input', () => {
// Arrange
const testDays = ['2026-01-01', '2026-01-02', '2026-01-03'];
// Act
fixture.componentRef.setInput('daysToShow', testDays);
fixture.detectChanges();
// Assert
expect(component.daysToShow()).toEqual(testDays);
});
it('should accept weeksToShow input', () => {
// Arrange
const testWeeks = 5;
// Act
fixture.componentRef.setInput('weeksToShow', testWeeks);
fixture.detectChanges();
// Assert
expect(component.weeksToShow()).toBe(testWeeks);
});
it('should accept firstDayOfWeek input', () => {
// Arrange
const testFirstDay = 1; // Monday
// Act
fixture.componentRef.setInput('firstDayOfWeek', testFirstDay);
fixture.detectChanges();
// Assert
expect(component.firstDayOfWeek()).toBe(testFirstDay);
});
it('should default weeksToShow to 6', () => {
// Act & Assert
expect(component.weeksToShow()).toBe(6);
});
it('should default firstDayOfWeek to 1', () => {
// Act & Assert
expect(component.firstDayOfWeek()).toBe(1);
});
});
});

View file

@ -253,7 +253,9 @@ describe('ScheduleService', () => {
// January 2026 starts on a Thursday, so with Sunday start,
// we should have padding days from December 2025
const firstDay = new Date(result[0]);
expect(firstDay.getMonth()).toBeLessThan(0); // December (previous year)
// December 2025 would be month 11 (previous year)
expect(firstDay.getMonth()).toBe(11);
expect(firstDay.getFullYear()).toBe(2025);
// Should also have some days from February if weeks extend past January
const lastDay = new Date(result[result.length - 1]);

View file

@ -173,8 +173,8 @@ describe('ScheduleComponent', () => {
});
it('should return true when _selectedDate matches today', () => {
// Arrange - set to today
const today = new Date();
// Arrange - set to today (must match the mock todayDateStr$ value)
const today = new Date('2026-01-20');
component['_selectedDate'].set(today);
// Act & Assert

View file

@ -128,11 +128,13 @@ describe('ArchiveOperationHandler', () => {
'updateTask',
'updateTasks',
'hasTask',
'hasTasksBatch',
'removeAllArchiveTasksForProject',
'removeTagsFromAllTasks',
'removeRepeatCfgFromArchiveTasks',
'unlinkIssueProviderFromArchiveTasks',
]);
mockTaskArchiveService.hasTasksBatch.and.returnValue(Promise.resolve(new Map()));
mockTimeTrackingService = jasmine.createSpyObj('TimeTrackingService', [
'cleanupDataEverywhereForProject',
'cleanupArchiveDataForTag',
@ -381,6 +383,16 @@ describe('ArchiveOperationHandler', () => {
describe('updateTasks action (batch)', () => {
it('should update multiple archived tasks for remote operations', async () => {
// Both tasks exist in archive
mockTaskArchiveService.hasTasksBatch.and.returnValue(
Promise.resolve(
new Map([
['task-1', true],
['task-2', true],
]),
),
);
const action = {
type: TaskSharedActions.updateTasks.type,
tasks: [
@ -415,8 +427,13 @@ describe('ArchiveOperationHandler', () => {
it('should only update tasks that exist in archive', async () => {
// Only task-1 is in archive, task-2 is not
mockTaskArchiveService.hasTask.and.callFake((id: string) =>
Promise.resolve(id === 'task-1'),
mockTaskArchiveService.hasTasksBatch.and.returnValue(
Promise.resolve(
new Map([
['task-1', true],
['task-2', false],
]),
),
);
const action = {