fix: 修复扩展管理对话框测试和代码质量问题

- 为 ActionSelectionStep.test.tsx 和 ExtensionListStep.test.tsx 添加 KeypressProvider 包裹
- 修复 KeypressContext 导入路径
- 更新测试快照
- 重构 ExtensionsManagerDialog:提取 enable/disable 公共逻辑到 handleToggleExtensionState
- 添加错误消息状态和用户友好的错误提示
This commit is contained in:
LaZzyMan 2026-02-28 16:38:10 +08:00
parent 4d27950a95
commit 0072c47996
5 changed files with 160 additions and 394 deletions

View file

@ -21,6 +21,7 @@ import { t } from '../../../i18n/index.js';
import type { Extension, Config } from '@qwen-code/qwen-code-core';
import { SettingScope, createDebugLogger } from '@qwen-code/qwen-code-core';
import { ExtensionUpdateState } from '../../state/extensions.js';
import { getErrorMessage } from '../../../utils/errors.js';
interface ExtensionsManagerDialogProps {
onClose: () => void;
@ -44,6 +45,7 @@ export function ExtensionsManagerDialog({
const [updateInProgress, setUpdateInProgress] = useState(false);
const [updateError, setUpdateError] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
// Load extensions
const loadExtensions = useCallback(async () => {
@ -94,6 +96,7 @@ export function ExtensionsManagerDialog({
const handleSelectExtension = useCallback((extensionIndex: number) => {
setSelectedExtensionIndex(extensionIndex);
setSuccessMessage(null); // Clear success message when navigating
setErrorMessage(null); // Clear error message when navigating
setNavigationStack((prev) => [...prev, MANAGEMENT_STEPS.ACTION_SELECTION]);
}, []);
@ -108,6 +111,8 @@ export function ExtensionsManagerDialog({
}
return prev.slice(0, -1);
});
// Clear messages when navigating back
setErrorMessage(null);
}, []);
const handleUpdateExtension = useCallback(async () => {
@ -195,8 +200,9 @@ export function ExtensionsManagerDialog({
[handleNavigateToStep, handleUpdateExtension],
);
const handleDisableExtension = useCallback(
async (scope: 'user' | 'workspace') => {
// Unified handler for toggling extension state (enable/disable)
const handleToggleExtensionState = useCallback(
async (scope: 'user' | 'workspace', newState: boolean) => {
if (!config || !selectedExtension) return;
try {
@ -208,77 +214,68 @@ export function ExtensionsManagerDialog({
const settingScope =
scope === 'user' ? SettingScope.User : SettingScope.Workspace;
await extensionManager.disableExtension(
selectedExtension.name,
settingScope,
);
if (newState) {
await extensionManager.enableExtension(
selectedExtension.name,
settingScope,
);
} else {
await extensionManager.disableExtension(
selectedExtension.name,
settingScope,
);
}
// Update local state
setExtensions((prev) =>
prev.map((ext) =>
ext.name === selectedExtension.name
? { ...ext, isActive: false }
? { ...ext, isActive: newState }
: ext,
),
);
// Show success message
const actionKey = newState ? 'enabled' : 'disabled';
setSuccessMessage(
t('Extension "{{name}}" disabled successfully.', {
t(`Extension "{{name}}" ${actionKey} successfully.`, {
name: selectedExtension.name,
}),
);
setErrorMessage(null);
// Go back to extension list to show success message
setNavigationStack([MANAGEMENT_STEPS.EXTENSION_LIST]);
} catch (error) {
debugLogger.error('Failed to disable extension:', error);
debugLogger.error(
`Failed to ${newState ? 'enable' : 'disable'} extension:`,
error,
);
setErrorMessage(
t('Failed to {{action}} extension "{{name}}": {{error}}', {
action: newState ? 'enable' : 'disable',
name: selectedExtension.name,
error: getErrorMessage(error),
}),
);
setSuccessMessage(null);
}
},
[config, selectedExtension],
);
const handleDisableExtension = useCallback(
async (scope: 'user' | 'workspace') => {
await handleToggleExtensionState(scope, false);
},
[handleToggleExtensionState],
);
const handleEnableExtension = useCallback(
async (scope: 'user' | 'workspace') => {
if (!config || !selectedExtension) return;
try {
const extensionManager = config.getExtensionManager();
if (!extensionManager) {
throw new Error('ExtensionManager not available');
}
const settingScope =
scope === 'user' ? SettingScope.User : SettingScope.Workspace;
await extensionManager.enableExtension(
selectedExtension.name,
settingScope,
);
// Update local state
setExtensions((prev) =>
prev.map((ext) =>
ext.name === selectedExtension.name
? { ...ext, isActive: true }
: ext,
),
);
// Show success message
setSuccessMessage(
t('Extension "{{name}}" enabled successfully.', {
name: selectedExtension.name,
}),
);
// Go back to extension list to show success message
setNavigationStack([MANAGEMENT_STEPS.EXTENSION_LIST]);
} catch (error) {
debugLogger.error('Failed to enable extension:', error);
}
await handleToggleExtensionState(scope, true);
},
[config, selectedExtension],
[handleToggleExtensionState],
);
const handleUninstallExtension = useCallback(
@ -394,6 +391,15 @@ export function ExtensionsManagerDialog({
const renderStepContent = useCallback(() => {
const currentStep = getCurrentStep();
// Show error message if present (only on extension list step)
if (errorMessage && currentStep === MANAGEMENT_STEPS.EXTENSION_LIST) {
return (
<Box flexDirection="column" gap={1}>
<Text color={theme.status.error}>{errorMessage}</Text>
</Box>
);
}
// Show success message if present (only on extension list step)
if (successMessage && currentStep === MANAGEMENT_STEPS.EXTENSION_LIST) {
return (
@ -489,6 +495,7 @@ export function ExtensionsManagerDialog({
updateInProgress,
updateError,
successMessage,
errorMessage,
handleSelectExtension,
handleNavigateToStep,
handleNavigateBack,

View file

@ -7,6 +7,7 @@
import { render } from 'ink-testing-library';
import { describe, it, expect, vi } from 'vitest';
import { ActionSelectionStep } from './ActionSelectionStep.js';
import { KeypressProvider } from '../../../contexts/KeypressContext.js';
import type { Extension } from '@qwen-code/qwen-code-core';
const createMockExtension = (name: string, isActive = true): Extension =>
@ -38,11 +39,13 @@ describe('ActionSelectionStep Snapshots', () => {
it('should render for active extension without update', () => {
const { lastFrame } = render(
<ActionSelectionStep
selectedExtension={createMockExtension('active-ext', true)}
hasUpdateAvailable={false}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ActionSelectionStep
selectedExtension={createMockExtension('active-ext', true)}
hasUpdateAvailable={false}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -50,11 +53,13 @@ describe('ActionSelectionStep Snapshots', () => {
it('should render for disabled extension', () => {
const { lastFrame } = render(
<ActionSelectionStep
selectedExtension={createMockExtension('disabled-ext', false)}
hasUpdateAvailable={false}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ActionSelectionStep
selectedExtension={createMockExtension('disabled-ext', false)}
hasUpdateAvailable={false}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -62,11 +67,13 @@ describe('ActionSelectionStep Snapshots', () => {
it('should render for extension with update available', () => {
const { lastFrame } = render(
<ActionSelectionStep
selectedExtension={createMockExtension('update-ext', true)}
hasUpdateAvailable={true}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ActionSelectionStep
selectedExtension={createMockExtension('update-ext', true)}
hasUpdateAvailable={true}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -74,11 +81,13 @@ describe('ActionSelectionStep Snapshots', () => {
it('should render for disabled extension with update', () => {
const { lastFrame } = render(
<ActionSelectionStep
selectedExtension={createMockExtension('disabled-update-ext', false)}
hasUpdateAvailable={true}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ActionSelectionStep
selectedExtension={createMockExtension('disabled-update-ext', false)}
hasUpdateAvailable={true}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -86,11 +95,13 @@ describe('ActionSelectionStep Snapshots', () => {
it('should render with no extension selected', () => {
const { lastFrame } = render(
<ActionSelectionStep
selectedExtension={null}
hasUpdateAvailable={false}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ActionSelectionStep
selectedExtension={null}
hasUpdateAvailable={false}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();

View file

@ -7,6 +7,7 @@
import { render } from 'ink-testing-library';
import { describe, it, expect, vi } from 'vitest';
import { ExtensionListStep } from './ExtensionListStep.js';
import { KeypressProvider } from '../../../contexts/KeypressContext.js';
import type { Extension } from '@qwen-code/qwen-code-core';
import { ExtensionUpdateState } from '../../../state/extensions.js';
@ -41,11 +42,13 @@ describe('ExtensionListStep Snapshots', () => {
it('should render empty state', () => {
const { lastFrame } = render(
<ExtensionListStep
extensions={[]}
extensionsUpdateState={new Map()}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ExtensionListStep
extensions={[]}
extensionsUpdateState={new Map()}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -54,11 +57,13 @@ describe('ExtensionListStep Snapshots', () => {
it('should render list with single extension', () => {
const extensions = [createMockExtension('test-extension', true)];
const { lastFrame } = render(
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={new Map()}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={new Map()}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -77,11 +82,13 @@ describe('ExtensionListStep Snapshots', () => {
]);
const { lastFrame } = render(
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -94,11 +101,13 @@ describe('ExtensionListStep Snapshots', () => {
]);
const { lastFrame } = render(
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();
@ -111,11 +120,13 @@ describe('ExtensionListStep Snapshots', () => {
]);
const { lastFrame } = render(
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>,
<KeypressProvider kittyProtocolEnabled={false}>
<ExtensionListStep
extensions={extensions}
extensionsUpdateState={updateState}
{...baseProps}
/>
</KeypressProvider>,
);
expect(lastFrame()).toMatchSnapshot();

View file

@ -1,166 +1,38 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`ActionSelectionStep Snapshots > should render for active extension without update 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- useSelectionList (src/ui/hooks/useSelectionList.ts:287:3)
- BaseSelectionList (src/ui/components/shared/BaseSelectionList.tsx:64:27)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
"
"● View Details
Disable Extension
Uninstall Extension
Back"
`;
exports[`ActionSelectionStep Snapshots > should render for disabled extension 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- useSelectionList (src/ui/hooks/useSelectionList.ts:287:3)
- BaseSelectionList (src/ui/components/shared/BaseSelectionList.tsx:64:27)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
"
"● View Details
Enable Extension
Uninstall Extension
Back"
`;
exports[`ActionSelectionStep Snapshots > should render for disabled extension with update 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- useSelectionList (src/ui/hooks/useSelectionList.ts:287:3)
- BaseSelectionList (src/ui/components/shared/BaseSelectionList.tsx:64:27)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
"
"● View Details
Update Extension
Enable Extension
Uninstall Extension
Back"
`;
exports[`ActionSelectionStep Snapshots > should render for extension with update available 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- useSelectionList (src/ui/hooks/useSelectionList.ts:287:3)
- BaseSelectionList (src/ui/components/shared/BaseSelectionList.tsx:64:27)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
"
"● View Details
Update Extension
Disable Extension
Uninstall Extension
Back"
`;
exports[`ActionSelectionStep Snapshots > should render with no extension selected 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- useSelectionList (src/ui/hooks/useSelectionList.ts:287:3)
- BaseSelectionList (src/ui/components/shared/BaseSelectionList.tsx:64:27)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
"
"● View Details
Enable Extension
Uninstall Extension
Back"
`;

View file

@ -1,171 +1,36 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`ExtensionListStep Snapshots > should render empty state 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- ExtensionListStep (src/ui/components/extensions/steps/ExtensionListStep.tsx:36:3)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
-workLoopSyn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.devel
opment.js:12644:41)
"
"No extensions installed.
Use '/extensions install' to install your first extension."
`;
exports[`ExtensionListStep Snapshots > should render list with multiple extensions 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
"● active-extension v1.0.0 (active) [up to date]
disabled-extension v1.0.0 (disabled) [not updatable]
update-available v1.0.0 (active) [update available]
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- ExtensionListStep (src/ui/components/extensions/steps/ExtensionListStep.tsx:36:3)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
-workLoopSyn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.devel
opment.js:12644:41)
"
3 extensions installed"
`;
exports[`ExtensionListStep Snapshots > should render list with single extension 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
"● test-extension v1.0.0 (active)
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- ExtensionListStep (src/ui/components/extensions/steps/ExtensionListStep.tsx:36:3)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
-workLoopSyn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.devel
opment.js:12644:41)
"
1 extensions installed"
`;
exports[`ExtensionListStep Snapshots > should render with checking status 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
"● checking-extension v1.0.0 (active) [checking for updates]
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- ExtensionListStep (src/ui/components/extensions/steps/ExtensionListStep.tsx:36:3)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
-workLoopSyn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.devel
opment.js:12644:41)
"
1 extensions installed"
`;
exports[`ExtensionListStep Snapshots > should render with error status 1`] = `
"
ERROR useKeypressContext must be used within a KeypressProvider
"● error-extension v1.0.0 (active) [error]
src/ui/contexts/KeypressContext.tsx:77:11
74: export function useKeypressContext() {
75: const context = useContext(KeypressContext);
76: if (!context) {
77: throw new Error(
78: 'useKeypressContext must be used within a KeypressProvider',
79: );
80: }
- useKeypressContext (src/ui/contexts/KeypressContext.tsx:77:11)
- useKeypress (src/ui/hooks/useKeypress.ts:24:38)
- ExtensionListStep (src/ui/components/extensions/steps/ExtensionListStep.tsx:36:3)
-Object.react-stack-bott (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reco
m-frame nciler.development.js:15859:20)
-renderWithHoo (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.dev
s elopment.js:3221:22)
-updateFunctionComp (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconcile
nent r.development.js:6475:19)
-beginWor (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.developm
ent.js:8009:18)
-runWithFiberIn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
EV velopment.js:1738:13)
-performUnitOfW (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.de
rk velopment.js:12834:22)
-workLoopSyn (/Users/mochi/code/qwen-code/node_modules/react-reconciler/cjs/react-reconciler.devel
opment.js:12644:41)
"
1 extensions installed"
`;