diff --git a/docs/architecture/stalker-portal.md b/docs/architecture/stalker-portal.md index b7cf1fade..14cc4cc48 100644 --- a/docs/architecture/stalker-portal.md +++ b/docs/architecture/stalker-portal.md @@ -488,6 +488,18 @@ Revisit both only with a portal that demonstrably fails without them. ### Regression coverage +**Writing tests against this section:** the decision chain has several exits — +no flag evidence, unresolvable command shape, `series` set, foreign host, +session unusable — and more than one of them can satisfy the same assertion. +Four tests in the PR that introduced this were found passing through an exit +other than the one they named (a foreign-host command reaches neither the +handshake nor `create_link`, so it silently stands in for "simple portal" or +"handshake failed"). Mutation testing does not catch it: it proves a test is +coupled to its target, not that it reached the mechanism in its name. Check the +mock setup against the execution path, and assert the step you mean was +actually taken — `expect(ensureToken).toHaveBeenCalled()` rather than only the +returned URL. + - `stalker-link-semantics.utils.spec.ts` — the decision table above. - `stalker-vod.utils.spec.ts` — both flags survive `buildStalkerSelectedVodItem` / `normalizeStalkerVodDetailsItem` / diff --git a/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-player-request.utils.spec.ts b/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-player-request.utils.spec.ts index 021332c5b..302f33ce5 100644 --- a/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-player-request.utils.spec.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-player-request.utils.spec.ts @@ -318,14 +318,20 @@ describe('stalker-player-request.utils', () => { }); it('skips the handshake for a simple portal', async () => { - await fetchStalkerPlaybackLink(deps(), { + // The command has to be PORTAL-OWNED, or the foreign-host early + // return would skip the handshake by itself and this would pass + // without saying anything about portal mode. `PLAYLIST` is a + // simple portal, so the skip here can only come from the mode. + const streamUrl = await fetchStalkerPlaybackLink(deps(), { playlist: PLAYLIST, selectedContentType: 'itv', - cmd: 'ffrt3 http://cdn.example/live/42.m3u8', + cmd: 'ffrt3 http://demo.example/live/42.m3u8', linkFlags: { use_http_tmp_link: '0' }, }); + expect(streamUrl).toBe('http://demo.example/live/42.m3u8'); expect(stalkerSession.ensureToken).not.toHaveBeenCalled(); + expect(dataService.sendIpcEvent).not.toHaveBeenCalled(); }); it('falls back to create_link when the handshake throws', async () => {