mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(epg): close a guide that never rendered rows without an EmptyError
whenRowsRendered used first(predicate), which errors when the source completes without a match. The CDK completes renderedRangeStream on destroy, so closing a guide opened on an empty scope raised an unhandled EmptyError. Use filter + take(1) instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
810e39379d
commit
f80a899212
2 files changed
+33
-3
No files matched your search
@@ -1,7 +1,7 @@
|
||||
import { ListRange } from '@angular/cdk/collections';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { DestroyRef } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { config, Subject } from 'rxjs';
|
||||
import { TimelineRenderBlock } from '../epg-timeline/epg-timeline-render.util';
|
||||
import { EPG_GUIDE_ROW_BUFFER } from './epg-guide-layout.util';
|
||||
import { EpgGuideChannel } from './epg-guide-source';
|
||||
@@ -220,6 +220,32 @@ describe('EpgGuideViewportController', () => {
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('closes cleanly when the viewport completes without ever rendering rows', async () => {
|
||||
const test = harness();
|
||||
const callback = jest.fn();
|
||||
const onUnhandledError = jest.fn();
|
||||
const previous = config.onUnhandledError;
|
||||
config.onUnhandledError = onUnhandledError;
|
||||
try {
|
||||
test.controller.whenRowsRendered(
|
||||
test.viewport,
|
||||
test.destroyRef,
|
||||
callback
|
||||
);
|
||||
// An empty scope: the CDK only ever reports an empty range, then
|
||||
// completes the stream when the guide closes.
|
||||
test.renderedRange$.next({ start: 0, end: 0 });
|
||||
test.renderedRange$.complete();
|
||||
// RxJS reports unhandled errors from a timeout.
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
} finally {
|
||||
config.onUnhandledError = previous;
|
||||
}
|
||||
|
||||
expect(onUnhandledError).not.toHaveBeenCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('drops the initial jump when the host is destroyed first', () => {
|
||||
const test = harness();
|
||||
const callback = jest.fn();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ListRange } from '@angular/cdk/collections';
|
||||
import { DestroyRef } from '@angular/core';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { first } from 'rxjs';
|
||||
import { filter, take } from 'rxjs';
|
||||
import { TimelineRenderBlock } from '../epg-timeline/epg-timeline-render.util';
|
||||
import { EpgGuideFocus } from './epg-guide-keyboard.controller';
|
||||
import { EPG_GUIDE_ROW_BUFFER } from './epg-guide-layout.util';
|
||||
@@ -115,7 +115,11 @@ export class EpgGuideViewportController {
|
||||
): void {
|
||||
viewport.renderedRangeStream
|
||||
.pipe(
|
||||
first((range) => range.end > range.start),
|
||||
// Not `first(predicate)`: the CDK completes the stream on
|
||||
// destroy, and a guide closed without ever having rows would
|
||||
// then raise an `EmptyError`.
|
||||
filter((range) => range.end > range.start),
|
||||
take(1),
|
||||
takeUntilDestroyed(destroyRef)
|
||||
)
|
||||
.subscribe(() => callback());
|
||||
|
||||
Reference in new issue
Block a user