mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
fix(cli): clean up slash command IDE listeners (#24397)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
committed by
GitHub
parent
cb289e0724
commit
cb35ee6710
@@ -858,11 +858,81 @@ describe('useSlashCommandProcessor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Lifecycle', () => {
|
describe('Lifecycle', () => {
|
||||||
|
it('removes the IDE status listener on unmount after async initialization', async () => {
|
||||||
|
let resolveIdeClient:
|
||||||
|
| ((client: {
|
||||||
|
addStatusChangeListener: (listener: () => void) => void;
|
||||||
|
removeStatusChangeListener: (listener: () => void) => void;
|
||||||
|
}) => void)
|
||||||
|
| undefined;
|
||||||
|
const addStatusChangeListener = vi.fn();
|
||||||
|
const removeStatusChangeListener = vi.fn();
|
||||||
|
|
||||||
|
mockIdeClientGetInstance.mockImplementation(
|
||||||
|
() =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolveIdeClient = resolve;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await setupProcessorHook();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
resolveIdeClient?.({
|
||||||
|
addStatusChangeListener,
|
||||||
|
removeStatusChangeListener,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
result.unmount();
|
||||||
|
unmountHook = undefined;
|
||||||
|
|
||||||
|
expect(addStatusChangeListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(removeStatusChangeListener).toHaveBeenCalledTimes(1);
|
||||||
|
expect(removeStatusChangeListener).toHaveBeenCalledWith(
|
||||||
|
addStatusChangeListener.mock.calls[0]?.[0],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not register an IDE status listener if unmounted before async initialization resolves', async () => {
|
||||||
|
let resolveIdeClient:
|
||||||
|
| ((client: {
|
||||||
|
addStatusChangeListener: (listener: () => void) => void;
|
||||||
|
removeStatusChangeListener: (listener: () => void) => void;
|
||||||
|
}) => void)
|
||||||
|
| undefined;
|
||||||
|
const addStatusChangeListener = vi.fn();
|
||||||
|
const removeStatusChangeListener = vi.fn();
|
||||||
|
|
||||||
|
mockIdeClientGetInstance.mockImplementation(
|
||||||
|
() =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolveIdeClient = resolve;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await setupProcessorHook();
|
||||||
|
|
||||||
|
result.unmount();
|
||||||
|
unmountHook = undefined;
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
resolveIdeClient?.({
|
||||||
|
addStatusChangeListener,
|
||||||
|
removeStatusChangeListener,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(addStatusChangeListener).not.toHaveBeenCalled();
|
||||||
|
expect(removeStatusChangeListener).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('should abort command loading when the hook unmounts', async () => {
|
it('should abort command loading when the hook unmounts', async () => {
|
||||||
const abortSpy = vi.spyOn(AbortController.prototype, 'abort');
|
const abortSpy = vi.spyOn(AbortController.prototype, 'abort');
|
||||||
const { unmount } = await setupProcessorHook();
|
const { unmount } = await setupProcessorHook();
|
||||||
|
|
||||||
unmount();
|
unmount();
|
||||||
|
unmountHook = undefined;
|
||||||
|
|
||||||
expect(abortSpy).toHaveBeenCalledTimes(1);
|
expect(abortSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -281,10 +281,16 @@ export const useSlashCommandProcessor = (
|
|||||||
const listener = () => {
|
const listener = () => {
|
||||||
reloadCommands();
|
reloadCommands();
|
||||||
};
|
};
|
||||||
|
let isActive = true;
|
||||||
|
let activeIdeClient: IdeClient | undefined;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
(async () => {
|
(async () => {
|
||||||
const ideClient = await IdeClient.getInstance();
|
const ideClient = await IdeClient.getInstance();
|
||||||
|
if (!isActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeIdeClient = ideClient;
|
||||||
ideClient.addStatusChangeListener(listener);
|
ideClient.addStatusChangeListener(listener);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -307,11 +313,8 @@ export const useSlashCommandProcessor = (
|
|||||||
coreEvents.on('extensionsStopping', extensionEventListener);
|
coreEvents.on('extensionsStopping', extensionEventListener);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
isActive = false;
|
||||||
(async () => {
|
activeIdeClient?.removeStatusChangeListener(listener);
|
||||||
const ideClient = await IdeClient.getInstance();
|
|
||||||
ideClient.removeStatusChangeListener(listener);
|
|
||||||
})();
|
|
||||||
removeMCPStatusChangeListener(listener);
|
removeMCPStatusChangeListener(listener);
|
||||||
coreEvents.off('extensionsStarting', extensionEventListener);
|
coreEvents.off('extensionsStarting', extensionEventListener);
|
||||||
coreEvents.off('extensionsStopping', extensionEventListener);
|
coreEvents.off('extensionsStopping', extensionEventListener);
|
||||||
|
|||||||
Reference in New Issue
Block a user