import {TestBed} from '@angular/core/testing'; import {of} from 'rxjs'; import {DbService} from '../db.service'; import {ShowDataService} from '../../modules/shows/services/show-data.service'; import {ShowSongDataService} from '../../modules/shows/services/show-song-data.service'; import {UserSessionService} from './user-session.service'; import {UserSongUsageService} from './user-song-usage.service'; describe('UserSongUsageService', () => { let service: UserSongUsageService; let dbServiceSpy: jasmine.SpyObj; let sessionSpy: jasmine.SpyObj; let showDataServiceSpy: jasmine.SpyObj; let showSongDataServiceSpy: jasmine.SpyObj; beforeEach(async () => { dbServiceSpy = jasmine.createSpyObj('DbService', ['doc']); sessionSpy = jasmine.createSpyObj('UserSessionService', ['update$'], { user$: of({id: 'user-1', role: 'admin', songUsage: {}}) as never, users$: of([{id: 'user-1'}, {id: 'user-2'}]) as never, }); showDataServiceSpy = jasmine.createSpyObj('ShowDataService', ['listRaw$']); showSongDataServiceSpy = jasmine.createSpyObj('ShowSongDataService', ['list$']); sessionSpy.update$.and.resolveTo(); showDataServiceSpy.listRaw$.and.returnValue( of([ {id: 'show-1', owner: 'user-1'}, {id: 'show-2', owner: 'user-2'}, ] as never) ); showSongDataServiceSpy.list$.and.callFake((showId: string) => of(showId === 'show-1' ? ([{songId: 'song-1'}, {songId: 'song-1'}, {songId: 'song-2'}] as never) : ([{songId: 'song-3'}] as never)) ); dbServiceSpy.doc.and.returnValue({update: jasmine.createSpy('update').and.resolveTo()} as never); await TestBed.configureTestingModule({ providers: [ {provide: DbService, useValue: dbServiceSpy}, {provide: UserSessionService, useValue: sessionSpy}, {provide: ShowDataService, useValue: showDataServiceSpy}, {provide: ShowSongDataService, useValue: showSongDataServiceSpy}, ], }); service = TestBed.inject(UserSongUsageService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should increment and decrement song usage for the current user', async () => { const updateSpy = jasmine.createSpy('update').and.resolveTo(); dbServiceSpy.doc.and.returnValue({update: updateSpy} as never); await service.incSongCount('song-1'); await service.decSongCount('song-2'); expect(dbServiceSpy.doc).toHaveBeenCalledWith('users/user-1'); expect(updateSpy.calls.argsFor(0)[0]).toEqual({'songUsage.song-1': jasmine.anything()}); expect(updateSpy.calls.argsFor(1)[0]).toEqual({'songUsage.song-2': jasmine.anything()}); }); it('should rebuild song usage for all users based on owned show songs', async () => { await expectAsync(service.rebuildSongUsage()).toBeResolvedTo({ usersProcessed: 2, showsProcessed: 2, showSongsProcessed: 4, }); expect(sessionSpy.update$).toHaveBeenCalledWith('user-1', {songUsage: {'song-1': 2, 'song-2': 1}}); expect(sessionSpy.update$).toHaveBeenCalledWith('user-2', {songUsage: {'song-3': 1}}); }); it('should reject song usage rebuilds for non-admin users', async () => { Object.defineProperty(sessionSpy, 'user$', {value: of({id: 'user-1', role: 'leader'})}); await expectAsync(service.rebuildSongUsage()).toBeRejectedWithError('Admin role required to rebuild songUsage.'); }); });