mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-12 04:19:25 -07:00
fix: stabilize failing test regressions across src and launcher lanes
- Fix log pruning cutoff math using BigInt `mtimeNs` to avoid Bun mtime precision loss - Fix stats CLI lifetime rebuild timestamp units in tests and log output; add `formatLoggedNumber` guard - Use `performance.now()` in subtitle sidebar auto-follow to isolate from test time injection - Harden renderer global cleanup tests with descriptor save/restore instead of assuming globals absent - Isolate `node:http` fallback in stats-server test with stub and assertion - Fix AniSkip fallback title: cleaned basename beats generic parent dirs; episode-only filenames still prefer series directory
This commit is contained in:
@@ -302,22 +302,28 @@ function setupPlaylistBrowserModalTest(options?: {
|
||||
}
|
||||
|
||||
test('playlist browser test cleanup must delete injected globals that were originally absent', () => {
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
|
||||
const env = setupPlaylistBrowserModalTest();
|
||||
|
||||
const previousWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window');
|
||||
const previousDocumentDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'document');
|
||||
try {
|
||||
Reflect.deleteProperty(globalThis, 'window');
|
||||
Reflect.deleteProperty(globalThis, 'document');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
|
||||
const env = setupPlaylistBrowserModalTest();
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), true);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), true);
|
||||
} finally {
|
||||
env.restore();
|
||||
}
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
assert.equal(typeof globalThis.window, 'undefined');
|
||||
assert.equal(typeof globalThis.document, 'undefined');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
assert.equal(typeof globalThis.window, 'undefined');
|
||||
assert.equal(typeof globalThis.document, 'undefined');
|
||||
} finally {
|
||||
restoreGlobalDescriptor('window', previousWindowDescriptor);
|
||||
restoreGlobalDescriptor('document', previousDocumentDescriptor);
|
||||
}
|
||||
});
|
||||
|
||||
test('playlist browser modal opens with playlist-focused current item selection', async () => {
|
||||
|
||||
@@ -74,6 +74,18 @@ function createListStub() {
|
||||
};
|
||||
}
|
||||
|
||||
test.afterEach(() => {
|
||||
if (Object.prototype.hasOwnProperty.call(globalThis, 'window') && globalThis.window === undefined) {
|
||||
Reflect.deleteProperty(globalThis, 'window');
|
||||
}
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(globalThis, 'document') &&
|
||||
globalThis.document === undefined
|
||||
) {
|
||||
Reflect.deleteProperty(globalThis, 'document');
|
||||
}
|
||||
});
|
||||
|
||||
test('findActiveSubtitleCueIndex prefers timing match before text fallback', () => {
|
||||
const cues = [
|
||||
{ startTime: 1, endTime: 2, text: 'same' },
|
||||
|
||||
@@ -8,6 +8,14 @@ const CLICK_SEEK_OFFSET_SEC = 0.08;
|
||||
const SNAPSHOT_POLL_INTERVAL_MS = 80;
|
||||
const EMBEDDED_SIDEBAR_MIN_WIDTH_PX = 240;
|
||||
const EMBEDDED_SIDEBAR_MAX_RATIO = 0.45;
|
||||
|
||||
function nowForUiTiming(): number {
|
||||
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
||||
return performance.now();
|
||||
}
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function subtitleCueListsEqual(a: SubtitleCue[], b: SubtitleCue[]): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
@@ -294,7 +302,7 @@ export function createSubtitleSidebarModal(
|
||||
!ctx.state.subtitleSidebarAutoScroll ||
|
||||
ctx.state.subtitleSidebarActiveCueIndex < 0 ||
|
||||
(!force && ctx.state.subtitleSidebarActiveCueIndex === previousActiveCueIndex) ||
|
||||
Date.now() < ctx.state.subtitleSidebarManualScrollUntilMs
|
||||
nowForUiTiming() < ctx.state.subtitleSidebarManualScrollUntilMs
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -547,7 +555,7 @@ export function createSubtitleSidebarModal(
|
||||
seekToCue(cue);
|
||||
});
|
||||
ctx.dom.subtitleSidebarList.addEventListener('wheel', () => {
|
||||
ctx.state.subtitleSidebarManualScrollUntilMs = Date.now() + MANUAL_SCROLL_HOLD_MS;
|
||||
ctx.state.subtitleSidebarManualScrollUntilMs = nowForUiTiming() + MANUAL_SCROLL_HOLD_MS;
|
||||
});
|
||||
ctx.dom.subtitleSidebarContent.addEventListener('mouseenter', async () => {
|
||||
subtitleSidebarHovered = true;
|
||||
|
||||
@@ -92,6 +92,17 @@ function restoreGlobalProp<K extends keyof typeof globalThis>(
|
||||
Reflect.deleteProperty(globalThis, key);
|
||||
}
|
||||
|
||||
function restoreGlobalDescriptor<K extends keyof typeof globalThis>(
|
||||
key: K,
|
||||
descriptor: PropertyDescriptor | undefined,
|
||||
) {
|
||||
if (descriptor) {
|
||||
Object.defineProperty(globalThis, key, descriptor);
|
||||
return;
|
||||
}
|
||||
Reflect.deleteProperty(globalThis, key);
|
||||
}
|
||||
|
||||
function setupYoutubePickerTestEnv(options?: {
|
||||
windowValue?: YoutubePickerTestWindow;
|
||||
customEventValue?: unknown;
|
||||
@@ -153,20 +164,30 @@ function setupYoutubePickerTestEnv(options?: {
|
||||
}
|
||||
|
||||
test('youtube picker test env restore deletes injected globals that were originally absent', () => {
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
const previousWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window');
|
||||
const previousDocumentDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'document');
|
||||
|
||||
const env = setupYoutubePickerTestEnv();
|
||||
try {
|
||||
Reflect.deleteProperty(globalThis, 'window');
|
||||
Reflect.deleteProperty(globalThis, 'document');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), true);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), true);
|
||||
const env = setupYoutubePickerTestEnv();
|
||||
|
||||
env.restore();
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), true);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), true);
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
assert.equal(typeof globalThis.window, 'undefined');
|
||||
assert.equal(typeof globalThis.document, 'undefined');
|
||||
env.restore();
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'window'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(globalThis, 'document'), false);
|
||||
assert.equal(typeof globalThis.window, 'undefined');
|
||||
assert.equal(typeof globalThis.document, 'undefined');
|
||||
} finally {
|
||||
restoreGlobalDescriptor('window', previousWindowDescriptor);
|
||||
restoreGlobalDescriptor('document', previousDocumentDescriptor);
|
||||
}
|
||||
});
|
||||
|
||||
test('youtube track picker close restores focus and mouse-ignore state', () => {
|
||||
|
||||
Reference in New Issue
Block a user