test(portals): follow the normalized restore state's new collection

`normalizeXtreamPendingRestoreState` now always emits `sourcePins`, like every
other collection it canonicalizes, so three specs that assert the exact
normalized shape had to follow. Adds coverage for the sanitizing itself: a pin
without a usable match key or content id is dropped, and a non-string
`updatedAt` is discarded rather than carried.

Caught by CI, not locally — the earlier full run served `playlist-shared-ui`
from the Nx cache, so it reported green on a stale result.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5 committed 2026-07-28 19:57:30 +02:00
1 parent 9deb4325e2
commit 7eaa681352
3 files changed
+47

No files matched your search

@@ -468,6 +468,8 @@ describe('PlaylistRefreshActionService', () => {
},
],
playbackPositions: [],
// Normalized state always carries every collection, empty or not.
sourcePins: [],
});
expect(store.dispatch).toHaveBeenCalledWith(
PlaylistActions.updatePlaylistMeta({
@@ -555,6 +555,8 @@ describe('RecentPlaylistsComponent busy state', () => {
},
],
playbackPositions: [],
// Normalized state always carries every collection, empty or not.
sourcePins: [],
});
expect(router.navigate).toHaveBeenCalledWith([
'/workspace',
@@ -6,6 +6,7 @@ describe('normalizeXtreamPendingRestoreState', () => {
favorites: [],
recentlyViewed: [],
playbackPositions: [],
sourcePins: [],
};
it.each([null, undefined, 'text', 42, []])(
@@ -17,6 +18,48 @@ describe('normalizeXtreamPendingRestoreState', () => {
}
);
describe('source pins', () => {
it('keeps usable pins and drops the rest', () => {
const state = normalizeXtreamPendingRestoreState({
sourcePins: [
{ matchKey: 'tmdb:603', contentId: 501 },
// Nothing addressable: writing either would occupy the
// unique key of a film it does not describe.
{ matchKey: '', contentId: 7 },
{ matchKey: 'title:dune:1984' },
{ contentId: 9 },
'not an object',
],
});
expect(state.sourcePins).toEqual([
{ matchKey: 'tmdb:603', contentId: 501 },
]);
});
it('keeps a string updatedAt and drops anything else', () => {
const state = normalizeXtreamPendingRestoreState({
sourcePins: [
{
matchKey: 'tmdb:603',
contentId: 501,
updatedAt: '2026-07-06T09:00:00.000Z',
},
{ matchKey: 'tmdb:604', contentId: 502, updatedAt: 17 },
],
});
expect(state.sourcePins).toEqual([
{
matchKey: 'tmdb:603',
contentId: 501,
updatedAt: '2026-07-06T09:00:00.000Z',
},
{ matchKey: 'tmdb:604', contentId: 502 },
]);
});
});
it('falls back to empty arrays for missing or non-array fields', () => {
expect(
normalizeXtreamPendingRestoreState({