import { TestBed } from '@angular/core/testing'; import { HttpClient } from '@angular/common/http'; import { Subject, of } from 'rxjs'; import { App } from './app'; import { DownloadsService } from './services/downloads.service'; import { SubscriptionsService } from './services/subscriptions.service'; import { CookieService } from 'ngx-cookie-service'; class DownloadsServiceStub { loading = false; queue = new Map(); done = new Map(); configuration: Record = { CUSTOM_DIRS: true, CREATE_CUSTOM_DIRS: true, ALLOW_YTDL_OPTIONS_OVERRIDES: false }; customDirs = { download_dir: [], audio_download_dir: [] }; queueChanged = new Subject(); doneChanged = new Subject(); configurationChanged = new Subject>(); customDirsChanged = new Subject>(); ytdlOptionsChanged = new Subject>(); updated = new Subject(); getCookieStatus() { return of({ status: 'ok', has_cookies: false }); } getPresets() { return of({ presets: ['Preset A'] }); } add() { return of({ status: 'ok' as const }); } cancelAdd() { return of({ status: 'ok' as const }); } startById() { return of({}); } delById() { return of({}); } delByFilter() { return of({}); } startByFilter() { return of({}); } uploadCookies() { return of({ status: 'ok' }); } deleteCookies() { return of({ status: 'ok' }); } } class SubscriptionsServiceStub { subscriptions = new Map(); subscriptionsChanged = new Subject(); subscribe() { return of({ status: 'ok' as const }); } delete() { return of({}); } refreshList() { return of([]); } } class CookieServiceStub { private cookies = new Map(); get(name: string) { return this.cookies.get(name) ?? ''; } set(name: string, value: string) { this.cookies.set(name, value); } check(name: string) { return this.cookies.has(name); } } describe('App', () => { let downloads: DownloadsServiceStub; beforeEach(async () => { Object.defineProperty(window, 'matchMedia', { writable: true, enumerable: true, value: vi.fn().mockImplementation((query: string) => ({ matches: false, media: query, onchange: null, addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); downloads = new DownloadsServiceStub(); await TestBed.configureTestingModule({ imports: [App], providers: [ { provide: DownloadsService, useValue: downloads }, { provide: SubscriptionsService, useClass: SubscriptionsServiceStub }, { provide: CookieService, useClass: CookieServiceStub }, { provide: HttpClient, useValue: { get: vi.fn().mockReturnValue(of({ 'yt-dlp': 'test', version: 'test' })), }, }, ], }).compileComponents(); }); it('should create the app', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; expect(app).toBeTruthy(); }); it('hides manual override input when disabled', () => { const fixture = TestBed.createComponent(App); fixture.componentInstance.isAdvancedOpen = true; fixture.detectChanges(); const root = fixture.nativeElement as HTMLElement; expect(root.querySelector('input[name="ytdlOptionsOverrides"]')).toBeNull(); const presetWrapper = root.querySelector('ng-select[name="ytdlOptionsPresets"]')?.closest('.col-12'); expect(presetWrapper?.classList.contains('col-md-6')).toBe(false); const presetRow = root.querySelector('ng-select[name="ytdlOptionsPresets"]')?.closest('.row'); expect(presetRow?.querySelector('input[name="checkIntervalMinutes"]')).toBeNull(); }); it('shows manual override input when enabled', () => { downloads.configuration['ALLOW_YTDL_OPTIONS_OVERRIDES'] = true; const fixture = TestBed.createComponent(App); fixture.componentInstance.isAdvancedOpen = true; fixture.detectChanges(); const root = fixture.nativeElement as HTMLElement; expect(root.querySelector('input[name="ytdlOptionsOverrides"]')).not.toBeNull(); const presetWrapper = root.querySelector('ng-select[name="ytdlOptionsPresets"]')?.closest('.col-12'); expect(presetWrapper?.classList.contains('col-md-6')).toBe(true); const presetRow = root.querySelector('ng-select[name="ytdlOptionsPresets"]')?.closest('.row'); expect(presetRow?.querySelector('input[name="checkIntervalMinutes"]')).toBeNull(); expect(presetRow?.querySelector('input[name="ytdlOptionsOverrides"]')).not.toBeNull(); }); it('does not submit manual overrides when disabled', () => { const fixture = TestBed.createComponent(App); const app = fixture.componentInstance; app.ytdlOptionsOverrides = '{"exec":"echo hi"}'; const payload = app['buildAddPayload'](); expect(payload.ytdlOptionsOverrides).toBe(''); }); });