mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-01 19:21:34 -07:00
fix(overlay): prevent field grouping modal from freezing overlay on Hyprland (#138)
This commit is contained in:
@@ -245,6 +245,12 @@ test('createFieldGroupingOverlayRuntime callback cancels and cleans up when kiku
|
||||
restoreOnModalClose: 'kiku',
|
||||
preferModalWindow: true,
|
||||
},
|
||||
// Abandonment also asks the renderer hosting the modal to close its dialog.
|
||||
{
|
||||
channel: 'kiku:field-grouping-cancel',
|
||||
restoreOnModalClose: undefined,
|
||||
preferModalWindow: true,
|
||||
},
|
||||
],
|
||||
);
|
||||
assert.deepEqual(waitCalls, [
|
||||
@@ -254,7 +260,76 @@ test('createFieldGroupingOverlayRuntime callback cancels and cleans up when kiku
|
||||
assert.deepEqual(warnings, [
|
||||
'Kiku field grouping modal did not acknowledge modal open on first attempt; retrying dedicated modal window.',
|
||||
]);
|
||||
assert.deepEqual(closed, ['kiku']);
|
||||
// Once from the send-failure path inside sendKikuFieldGroupingRequest, once from the
|
||||
// callback's abandonment cleanup. The real runtime guards this via the restore set, so
|
||||
// the duplicate is a harmless no-op.
|
||||
assert.deepEqual(closed, ['kiku', 'kiku']);
|
||||
} finally {
|
||||
globalThis.setTimeout = originalSetTimeout;
|
||||
}
|
||||
});
|
||||
|
||||
test('createFieldGroupingOverlayRuntime prepares overlay windows before opening the modal', async () => {
|
||||
// The field grouping modal must run the same prerequisites as every other modal
|
||||
// (openOverlayHostedModal) so it opens with the overlay runtime ready and the visible overlay
|
||||
// window present — otherwise on Hyprland it fails to sit above / focus over fullscreen mpv.
|
||||
const order: string[] = [];
|
||||
const originalSetTimeout = globalThis.setTimeout;
|
||||
// The modal acknowledges open below, so the callback stays pending and arms its response
|
||||
// timeout; stub the timer so no real 90s handle leaks into the test runner.
|
||||
globalThis.setTimeout = (() => 0) as unknown as typeof globalThis.setTimeout;
|
||||
|
||||
try {
|
||||
const runtime = createFieldGroupingOverlayRuntime<'kiku'>({
|
||||
getMainWindow: () => null,
|
||||
getVisibleOverlayVisible: () => false,
|
||||
setVisibleOverlayVisible: () => {},
|
||||
getResolver: () => null,
|
||||
setResolver: () => {},
|
||||
getRestoreVisibleOverlayOnModalClose: () => new Set<'kiku'>(),
|
||||
ensureOverlayStartupPrereqs: () => order.push('prereqs'),
|
||||
ensureOverlayWindowsReadyForVisibilityActions: () => order.push('windows-ready'),
|
||||
sendToVisibleOverlay: (channel) => {
|
||||
order.push(`send:${channel}`);
|
||||
return true;
|
||||
},
|
||||
waitForModalOpen: async () => {
|
||||
order.push('wait');
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// Do not await: an acknowledged modal leaves the choice pending until the user responds.
|
||||
void runtime.createFieldGroupingCallback()({
|
||||
original: {
|
||||
noteId: 1,
|
||||
expression: 'a',
|
||||
sentencePreview: 'a',
|
||||
hasAudio: false,
|
||||
hasImage: false,
|
||||
isOriginal: true,
|
||||
},
|
||||
duplicate: {
|
||||
noteId: 2,
|
||||
expression: 'b',
|
||||
sentencePreview: 'b',
|
||||
hasAudio: false,
|
||||
hasImage: false,
|
||||
isOriginal: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Let the async send + modal-open ack chain run.
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
assert.deepEqual(order, [
|
||||
'prereqs',
|
||||
'windows-ready',
|
||||
'send:kiku:field-grouping-request',
|
||||
'wait',
|
||||
]);
|
||||
} finally {
|
||||
globalThis.setTimeout = originalSetTimeout;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user