From ad5b132cdada98ddb4bf540bf1d3d8e55d515b9c Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 26 Sep 2026 04:21:05 +0200 Subject: [PATCH] test(xtream): move the parental-lock reload specs beside the content spec The content feature spec sits at the 1200-line spec cap. Co-Authored-By: Claude Fable 5.1 --- .../with-content.feature.reload.spec.ts | 124 ++++++++++++++++++ .../features/with-content.feature.spec.ts | 40 ------ 2 files changed, 124 insertions(+), 40 deletions(-) create mode 100644 libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.reload.spec.ts diff --git a/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.reload.spec.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.reload.spec.ts new file mode 100644 index 000000000..8972268ac --- /dev/null +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.reload.spec.ts @@ -0,0 +1,124 @@ +import { TestBed } from '@angular/core/testing'; +import { PortalStatusType } from '../../xtream-state'; +import { + createContentTestProviders, + createContentTestStore, + createPendingRestoreServiceMock, +} from './with-content.feature.spec-helpers'; + +jest.mock('@iptvnator/portal/shared/util', () => ({ + createLogger: () => ({ + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }), +})); + +type ContentType = 'live' | 'movie' | 'series'; + +const TestContentStore = createContentTestStore(() => + Promise.resolve('active' as PortalStatusType) +); + +/** + * Parental-lock reloads (`reloadCategories` / `reloadCachedContent`) fail + * closed. Split from `with-content.feature.spec.ts`, which sits at the spec + * line cap. + */ +describe('withContent parental-lock reloads', () => { + let store: InstanceType; + let dataSource: { + getCategories: jest.Mock; + getCachedCategories: jest.Mock; + getContent: jest.Mock; + getCachedContent: jest.Mock; + hasCategories: jest.Mock; + hasContent: jest.Mock; + restoreUserData: jest.Mock; + }; + + beforeEach(() => { + localStorage.clear(); + dataSource = { + getCategories: jest.fn().mockResolvedValue([]), + getCachedCategories: jest.fn().mockResolvedValue([]), + getContent: jest.fn().mockResolvedValue([]), + getCachedContent: jest.fn().mockResolvedValue([]), + hasCategories: jest.fn().mockResolvedValue(true), + hasContent: jest.fn().mockResolvedValue(false), + restoreUserData: jest.fn().mockResolvedValue(undefined), + }; + TestBed.configureTestingModule({ + providers: createContentTestProviders(TestContentStore, { + dataSource, + databaseService: { + clearXtreamImportCache: jest.fn().mockResolvedValue(true), + cancelOperation: jest.fn().mockResolvedValue(true), + createOperationId: jest.fn( + (prefix?: string) => `${prefix ?? 'db-op'}-1` + ), + getXtreamImportStatus: jest + .fn() + .mockResolvedValue('completed'), + setXtreamImportStatus: jest.fn().mockResolvedValue(true), + supportsDbOperationCancellation: jest + .fn() + .mockReturnValue(true), + }, + xtreamApiService: { + cancelSession: jest.fn().mockResolvedValue(true), + }, + pendingRestoreService: createPendingRestoreServiceMock(), + dataService: { + sendIpcEvent: jest + .fn() + .mockResolvedValue({ success: true }), + }, + }), + }); + store = TestBed.inject(TestContentStore); + }); + + afterEach(() => localStorage.clear()); + + it('empties the category lists when their reload fails', async () => { + dataSource.getCategories.mockResolvedValue([{ category_id: 'x' }]); + await store.reloadCategories(); + expect(store.liveCategories()).toEqual([{ category_id: 'x' }]); + + dataSource.getCategories.mockRejectedValue(new Error('db')); + await store.reloadCategories(); + + expect(store.liveCategories()).toEqual([]); + expect(store.vodCategories()).toEqual([]); + expect(store.serialCategories()).toEqual([]); + }); + + it('empties a type whose cached reload fails and lets the others reload', async () => { + dataSource.getContent.mockResolvedValue([{ xtream_id: 1 }]); + await store.initializeContent(); + expect(store.contentLoadStateByType()).toEqual({ + live: 'ready', + vod: 'ready', + series: 'ready', + }); + + dataSource.getContent.mockImplementation( + (_playlistId: string, _credentials: unknown, type: ContentType) => + type === 'movie' + ? Promise.reject(new Error('db')) + : Promise.resolve([{ xtream_id: 2 }]) + ); + await store.reloadCachedContent(); + + expect(store.vodStreams()).toEqual([]); + expect(store.liveStreams()).toEqual([{ xtream_id: 2 }]); + expect(store.serialStreams()).toEqual([{ xtream_id: 2 }]); + expect(store.contentLoadStateByType()).toEqual({ + live: 'ready', + vod: 'idle', + series: 'ready', + }); + }); +}); diff --git a/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.spec.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.spec.ts index f49fc73e2..6dd3ec5c5 100644 --- a/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.spec.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.spec.ts @@ -462,46 +462,6 @@ describe('withContent import state', () => { expect(store.isContentInitialized()).toBe(true); }); - it('empties the category lists when their reload fails', async () => { - dataSource.getCategories.mockResolvedValue([{ category_id: 'x' }]); - await store.reloadCategories(); - expect(store.liveCategories()).toEqual([{ category_id: 'x' }]); - - dataSource.getCategories.mockRejectedValue(new Error('db')); - await store.reloadCategories(); - - expect(store.liveCategories()).toEqual([]); - expect(store.vodCategories()).toEqual([]); - expect(store.serialCategories()).toEqual([]); - }); - - it('empties a type whose cached reload fails and lets the others reload', async () => { - dataSource.getContent.mockResolvedValue([{ xtream_id: 1 }]); - await store.initializeContent(); - expect(store.contentLoadStateByType()).toEqual({ - live: 'ready', - vod: 'ready', - series: 'ready', - }); - - dataSource.getContent.mockImplementation( - (_playlistId: string, _credentials: unknown, type: ContentType) => - type === 'movie' - ? Promise.reject(new Error('db')) - : Promise.resolve([{ xtream_id: 2 }]) - ); - await store.reloadCachedContent(); - - expect(store.vodStreams()).toEqual([]); - expect(store.liveStreams()).toEqual([{ xtream_id: 2 }]); - expect(store.serialStreams()).toEqual([{ xtream_id: 2 }]); - expect(store.contentLoadStateByType()).toEqual({ - live: 'ready', - vod: 'idle', - series: 'ready', - }); - }); - it('records the VOD category owner when categories are reloaded', async () => { dataSource.getCategories.mockImplementation( (