From 3a93f566711beec5600ac49dc50fc34be849b69c Mon Sep 17 00:00:00 2001 From: Seydi Charyyev Date: Wed, 24 Jun 2026 23:53:53 +0500 Subject: [PATCH] fix(desktop): show optimistic toggle state when disabling an extension (#9882) Signed-off-by: Seydi Charyyev --- .../subcomponents/ExtensionItem.test.tsx | 47 +++++++++++++++++++ .../subcomponents/ExtensionItem.tsx | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.test.tsx diff --git a/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.test.tsx b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.test.tsx new file mode 100644 index 000000000..f8d1801ff --- /dev/null +++ b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.test.tsx @@ -0,0 +1,47 @@ +import { describe, it, expect, vi } from 'vitest'; +import { render, type RenderOptions, screen, fireEvent, waitFor } from '@testing-library/react'; +import ExtensionItem from './ExtensionItem'; +import { IntlTestWrapper } from '../../../../i18n/test-utils'; +import type { FixedExtensionEntry } from '../../../ConfigContext'; + +vi.mock('./ExtensionList', () => ({ + getSubtitle: () => ({ description: '', command: '' }), + getFriendlyTitle: (ext: { name: string }) => ext.name, +})); + +const renderWithIntl = (ui: React.ReactElement, options?: RenderOptions) => + render(ui, { wrapper: IntlTestWrapper, ...options }); + +const makeExtension = (enabled: boolean): FixedExtensionEntry => + ({ name: 'developer', type: 'builtin', enabled }) as unknown as FixedExtensionEntry; + +describe('ExtensionItem', () => { + it('reflects the toggle as OFF immediately when disabling, before the async toggle resolves', async () => { + // onToggle stays pending so we observe the in-flight (optimistic) state + const onToggle = vi.fn(() => new Promise(() => {})); + renderWithIntl(); + + const toggle = screen.getByRole('switch'); + expect(toggle).toHaveAttribute('aria-checked', 'true'); + + fireEvent.click(toggle); + + await waitFor(() => { + expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'false'); + }); + }); + + it('reflects the toggle as ON immediately when enabling, before the async toggle resolves', async () => { + const onToggle = vi.fn(() => new Promise(() => {})); + renderWithIntl(); + + const toggle = screen.getByRole('switch'); + expect(toggle).toHaveAttribute('aria-checked', 'false'); + + fireEvent.click(toggle); + + await waitFor(() => { + expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'true'); + }); + }); +}); diff --git a/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.tsx b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.tsx index 8c4360830..4552ee844 100644 --- a/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.tsx +++ b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionItem.tsx @@ -106,7 +106,7 @@ export default function ExtensionItem({ )} handleToggle(extension)} disabled={isToggling} variant="mono"