test(focus-mode,backup): add missing service providers to fix 150+ failing tests

- Add GlobalTrackingIntervalService and TakeABreakService providers to FocusMode test suites
- Add selectIsResumingBreak selector overrides to bug #5875 tests
- Update BackupService test expectations for dual-archive architecture (no merge)
- All 6,412 unit tests now passing
This commit is contained in:
Johannes Millan 2026-01-19 20:30:52 +01:00
parent 548ec8b6cb
commit 02430a34c7
5 changed files with 85 additions and 9 deletions

View file

@ -31,6 +31,8 @@ import { TaskService } from '../../tasks/task.service';
import { BannerService } from '../../../core/banner/banner.service';
import { MetricService } from '../../metric/metric.service';
import { FocusModeStorageService } from '../focus-mode-storage.service';
import { GlobalTrackingIntervalService } from '../../../core/global-tracking-interval/global-tracking-interval.service';
import { TakeABreakService } from '../../take-a-break/take-a-break.service';
import * as actions from './focus-mode.actions';
import * as selectors from './focus-mode.selectors';
import { FocusModeMode, FocusScreen, TimerState } from '../focus-mode.model';
@ -88,6 +90,10 @@ describe('FocusMode Bug #5875: Pomodoro timer sync issues', () => {
logFocusSession: jasmine.createSpy('logFocusSession'),
};
const takeABreakServiceMock = {
otherNoBreakTIme$: new BehaviorSubject<number>(0),
};
TestBed.configureTestingModule({
providers: [
FocusModeEffects,
@ -126,6 +132,13 @@ describe('FocusMode Bug #5875: Pomodoro timer sync issues', () => {
provide: FocusModeStorageService,
useValue: { setLastCountdownDuration: jasmine.createSpy() },
},
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});
@ -152,6 +165,7 @@ describe('FocusMode Bug #5875: Pomodoro timer sync issues', () => {
store.overrideSelector(selectors.selectMode, FocusModeMode.Pomodoro);
store.overrideSelector(selectors.selectCurrentScreen, FocusScreen.Break);
store.overrideSelector(selectors.selectPausedTaskId, null);
store.overrideSelector(selectors.selectIsResumingBreak, false);
store.refreshState();
effects = TestBed.inject(FocusModeEffects);
@ -187,6 +201,7 @@ describe('FocusMode Bug #5875: Pomodoro timer sync issues', () => {
store.overrideSelector(selectors.selectMode, FocusModeMode.Pomodoro);
store.overrideSelector(selectors.selectCurrentScreen, FocusScreen.Break);
store.overrideSelector(selectors.selectPausedTaskId, null);
store.overrideSelector(selectors.selectIsResumingBreak, false);
store.refreshState();
effects = TestBed.inject(FocusModeEffects);

View file

@ -29,6 +29,7 @@ import { BannerService } from '../../../core/banner/banner.service';
import { MetricService } from '../../metric/metric.service';
import { FocusModeStorageService } from '../focus-mode-storage.service';
import { TakeABreakService } from '../../take-a-break/take-a-break.service';
import { GlobalTrackingIntervalService } from '../../../core/global-tracking-interval/global-tracking-interval.service';
import * as actions from './focus-mode.actions';
import * as selectors from './focus-mode.selectors';
import { FocusModeMode, FocusScreen, TimerState } from '../focus-mode.model';
@ -153,6 +154,12 @@ describe('FocusMode Bug #5995: Resume paused break', () => {
{ provide: MetricService, useValue: metricServiceMock },
{ provide: FocusModeStorageService, useValue: {} },
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});

View file

@ -9,6 +9,8 @@ import { TaskService } from '../../tasks/task.service';
import { BannerService } from '../../../core/banner/banner.service';
import { MetricService } from '../../metric/metric.service';
import { FocusModeStorageService } from '../focus-mode-storage.service';
import { GlobalTrackingIntervalService } from '../../../core/global-tracking-interval/global-tracking-interval.service';
import { TakeABreakService } from '../../take-a-break/take-a-break.service';
import * as actions from './focus-mode.actions';
import * as selectors from './focus-mode.selectors';
import { FocusModeMode, FocusScreen, TimerState } from '../focus-mode.model';
@ -83,6 +85,10 @@ describe('FocusModeEffects', () => {
.and.returnValue(false),
};
const takeABreakServiceMock = {
otherNoBreakTIme$: new BehaviorSubject<number>(0),
};
TestBed.configureTestingModule({
providers: [
FocusModeEffects,
@ -120,6 +126,13 @@ describe('FocusModeEffects', () => {
useValue: { setLastCountdownDuration: jasmine.createSpy() },
},
{ provide: HydrationStateService, useValue: hydrationStateServiceMock },
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});

View file

@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { of, ReplaySubject, Subject, Subscription } from 'rxjs';
import { of, ReplaySubject, Subject, Subscription, BehaviorSubject } from 'rxjs';
import { take } from 'rxjs/operators';
import { Action } from '@ngrx/store';
import { FocusModeMode } from '../focus-mode.model';
@ -16,6 +16,8 @@ import { FocusModeStrategyFactory } from '../focus-mode-strategies';
import { MetricService } from '../../metric/metric.service';
import { FocusModeStorageService } from '../focus-mode-storage.service';
import { selectFocusModeConfig } from '../../config/store/global-config.reducer';
import { GlobalTrackingIntervalService } from '../../../core/global-tracking-interval/global-tracking-interval.service';
import { TakeABreakService } from '../../take-a-break/take-a-break.service';
describe('FocusMode Flowtime behavior', () => {
describe('Reducer: startFocusSession', () => {
@ -93,6 +95,9 @@ describe('FocusMode Flowtime behavior', () => {
let actions$: ReplaySubject<Action>;
let storageService: jasmine.SpyObj<FocusModeStorageService>;
let effects: FocusModeEffects;
const takeABreakServiceMock = {
otherNoBreakTIme$: new BehaviorSubject<number>(0),
};
beforeEach(() => {
actions$ = new ReplaySubject<Action>(1);
@ -129,6 +134,13 @@ describe('FocusMode Flowtime behavior', () => {
'setLastCountdownDuration',
]),
},
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});
store = TestBed.inject(MockStore);
@ -315,6 +327,9 @@ describe('FocusMode Flowtime behavior', () => {
duration: 45_000,
purpose: 'work' as const,
};
const takeABreakServiceMock = {
otherNoBreakTIme$: new BehaviorSubject<number>(0),
};
beforeEach(() => {
actions$ = new ReplaySubject<Action>(1);
@ -351,6 +366,13 @@ describe('FocusMode Flowtime behavior', () => {
'setLastCountdownDuration',
]),
},
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});
@ -410,6 +432,9 @@ describe('FocusMode Flowtime behavior', () => {
let effects: FocusModeEffects;
let actions$: Subject<Action>;
let getStrategySpy: jasmine.Spy;
const takeABreakServiceMock = {
otherNoBreakTIme$: new BehaviorSubject<number>(0),
};
beforeEach(() => {
actions$ = new Subject<Action>();
@ -449,6 +474,13 @@ describe('FocusMode Flowtime behavior', () => {
'setLastCountdownDuration',
]),
},
{ provide: TakeABreakService, useValue: takeABreakServiceMock },
{
provide: GlobalTrackingIntervalService,
useValue: {
todayStr$: new BehaviorSubject<string>('2024-01-19'),
},
},
],
});

View file

@ -191,8 +191,8 @@ describe('BackupService', () => {
expect(calledWith.task.ids).toContain('archived-task-1');
});
it('should write archiveOld to IndexedDB when present in backup', async () => {
// Note: dataRepair merges archiveOld into archiveYoung, but both are still written
it('should write archiveOld separately to IndexedDB when present in backup', async () => {
// Note: Dual-archive architecture keeps archives separate (no merge)
const archiveOld = createArchiveModel('archived-task-old', 'Archived Task Old');
const backupData = {
...createMinimalValidBackup(),
@ -202,15 +202,19 @@ describe('BackupService', () => {
await service.importCompleteBackup(backupData as any, true, true);
// After dataRepair, archiveOld is empty (merged into archiveYoung)
// Both should be written
// Both archives should be written
expect(mockArchiveDbAdapter.saveArchiveYoung).toHaveBeenCalled();
expect(mockArchiveDbAdapter.saveArchiveOld).toHaveBeenCalled();
// The archiveOld task should have been merged into archiveYoung by dataRepair
// archiveOld remains separate - verify it was written to IndexedDB
const oldCalledWith =
mockArchiveDbAdapter.saveArchiveOld.calls.mostRecent().args[0];
expect(oldCalledWith.task.ids).toContain('archived-task-old');
// archiveYoung should remain empty (no merge happened)
const youngCalledWith =
mockArchiveDbAdapter.saveArchiveYoung.calls.mostRecent().args[0];
expect(youngCalledWith.task.ids).toContain('archived-task-old');
expect(youngCalledWith.task.ids).toEqual([]);
});
it('should write both archiveYoung and archiveOld when both present', async () => {
@ -227,11 +231,16 @@ describe('BackupService', () => {
expect(mockArchiveDbAdapter.saveArchiveYoung).toHaveBeenCalled();
expect(mockArchiveDbAdapter.saveArchiveOld).toHaveBeenCalled();
// dataRepair merges archiveOld into archiveYoung
// Dual-archive architecture: verify both written separately (no merge)
const youngCalledWith =
mockArchiveDbAdapter.saveArchiveYoung.calls.mostRecent().args[0];
expect(youngCalledWith.task.ids).toContain('young-task');
expect(youngCalledWith.task.ids).toContain('old-task');
expect(youngCalledWith.task.ids).not.toContain('old-task');
const oldCalledWith =
mockArchiveDbAdapter.saveArchiveOld.calls.mostRecent().args[0];
expect(oldCalledWith.task.ids).toContain('old-task');
expect(oldCalledWith.task.ids).not.toContain('young-task');
});
it('should write default empty archives when not present in backup (added by dataRepair)', async () => {