| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- import { fakeAsync, flushMicrotasks, TestBed, tick } from '@angular/core/testing';
- import { Subject } from 'rxjs';
- import { NavigationEnd, Router } from '@angular/router';
- import { OperationsService } from './operations.service';
- import { OperationsLiveRefreshService } from './operations-live-refresh.service';
- import { ADMIN_SESSION_KEY } from './admin.constants';
- describe('OperationsLiveRefreshService', () => {
- let changes: Subject<'local' | 'broadcast'>;
- let request: jasmine.Spy;
- let routerEvents: Subject<NavigationEnd>;
- let router: { url: string; events: Subject<NavigationEnd>; getCurrentNavigation: () => null; parseUrl: (url: string) => { toString: () => string } };
- beforeEach(() => {
- changes = new Subject();
- request = jasmine.createSpy('request');
- routerEvents = new Subject<NavigationEnd>();
- router = { url: '/admin/members', events: routerEvents, getCurrentNavigation: () => null, parseUrl: (url) => ({ toString: () => url }) };
- sessionStorage.setItem(ADMIN_SESSION_KEY, JSON.stringify({ sessionToken: 'test-session' }));
- TestBed.configureTestingModule({
- providers: [
- OperationsLiveRefreshService,
- { provide: OperationsService, useValue: { request, dataChanges$: changes } },
- { provide: Router, useValue: router },
- ],
- });
- });
- afterEach(() => sessionStorage.removeItem(ADMIN_SESSION_KEY));
- it('checks on entry without polling or reloading the page afterward', fakeAsync(() => {
- request.and.returnValue(Promise.resolve(version('v1')));
- const refresh = jasmine.createSpy('refresh');
- const stop = TestBed.inject(OperationsLiveRefreshService).watch(['learning'], refresh);
- flushMicrotasks();
- expect(refresh).not.toHaveBeenCalled();
- tick(15_000);
- flushMicrotasks();
- expect(request).toHaveBeenCalledTimes(1);
- expect(refresh).not.toHaveBeenCalled();
- stop();
- }));
- it('reloads immediately after local and cross-tab writes', () => {
- request.and.returnValue(Promise.resolve(version('v1')));
- const refresh = jasmine.createSpy('refresh');
- const stop = TestBed.inject(OperationsLiveRefreshService).watch(['appointments'], refresh);
- changes.next('local');
- changes.next('broadcast');
- expect(refresh).toHaveBeenCalledTimes(2);
- stop();
- });
- it('stops checking after logout', fakeAsync(() => {
- request.and.returnValue(Promise.resolve(version('v1')));
- const stop = TestBed.inject(OperationsLiveRefreshService).watch(['learning'], () => undefined);
- flushMicrotasks();
- expect(request).toHaveBeenCalledTimes(1);
- sessionStorage.removeItem(ADMIN_SESSION_KEY);
- tick(10_000);
- flushMicrotasks();
- expect(request).toHaveBeenCalledTimes(1);
- stop();
- }));
- it('does not check again when a detached page is reattached', fakeAsync(() => {
- request.and.returnValues(Promise.resolve(version('v1')), Promise.resolve(version('v2')));
- const refresh = jasmine.createSpy('refresh');
- const stop = TestBed.inject(OperationsLiveRefreshService).watch(['learning'], refresh);
- flushMicrotasks();
- router.url = '/admin/schedule';
- routerEvents.next(new NavigationEnd(1, '/admin/members', '/admin/schedule'));
- tick(10_000);
- flushMicrotasks();
- expect(request).toHaveBeenCalledTimes(1);
- changes.next('local');
- expect(refresh).not.toHaveBeenCalled();
- router.url = '/admin/members';
- routerEvents.next(new NavigationEnd(2, '/admin/schedule', '/admin/members'));
- flushMicrotasks();
- expect(request).toHaveBeenCalledTimes(1);
- expect(refresh).not.toHaveBeenCalled();
- stop();
- }));
- });
- function version(value: string) {
- return { version: value, scopeVersions: { learning: value }, refreshedAt: '2026-09-25T00:00:00.000Z', syncStatus: { state: 'current' as const } };
- }
|