Skip to content

Commit 3e3d324

Browse files
committed
fix(modes): address parser consistency, UI desync, and test coverage issues
- Use parseYamlSafely() in importModeWithRules for consistent YAML parsing across the codebase, ensuring BOM stripping and character cleaning - Sync visualMode with context.mode to prevent UI desync when modes are switched programmatically from outside the component - Add test coverage for fallback branch when imported mode slug is not yet present in customModes state Fixes parser inconsistency (P2), visualMode desync risk (P3), and missing test coverage (P3) identified in code review.
1 parent 6fe074d commit 3e3d324

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

src/core/config/CustomModesManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ export class CustomModesManager {
932932
// Parse the YAML content with proper type validation
933933
let importData: ImportData
934934
try {
935-
const parsed = yaml.parse(yamlContent)
935+
const parsed = this.parseYamlSafely(yamlContent, '')
936936

937937
// Validate the structure
938938
if (!parsed?.customModes || !Array.isArray(parsed.customModes) || parsed.customModes.length === 0) {

webview-ui/src/components/modes/ModesView.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
205205
switchModeRef.current = switchMode
206206
}, [switchMode])
207207

208+
// Sync visualMode with backend mode changes to prevent desync
209+
useEffect(() => {
210+
setVisualMode(mode)
211+
}, [mode])
212+
208213
// Handler for popover open state change
209214
const onOpenChange = useCallback((open: boolean) => {
210215
setOpen(open)

webview-ui/src/components/modes/__tests__/ModesView.import-switch.spec.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,28 @@ describe("ModesView - auto switch after import", () => {
9191
})
9292
expect(trigger).toHaveTextContent("Code")
9393
})
94+
95+
it("uses fallback branch when imported slug not yet present in customModes", async () => {
96+
// Render with empty customModes - imported mode hasn't been added to state yet
97+
render(
98+
<ExtensionStateContext.Provider value={{ ...baseState, customModes: [] } as any}>
99+
<ModesView onDone={vitest.fn()} />
100+
</ExtensionStateContext.Provider>,
101+
)
102+
103+
const trigger = screen.getByTestId("mode-select-trigger")
104+
expect(trigger).toHaveTextContent("Code")
105+
106+
// Simulate successful import for a slug not yet in customModes (timing race condition)
107+
window.dispatchEvent(
108+
new MessageEvent("message", {
109+
data: { type: "importModeResult", success: true, slug: "not-yet-loaded-mode" },
110+
}),
111+
)
112+
113+
// Fallback branch should send backend switch message
114+
await waitFor(() => {
115+
expect(vscode.postMessage).toHaveBeenCalledWith({ type: "mode", text: "not-yet-loaded-mode" })
116+
})
117+
})
94118
})

0 commit comments

Comments
 (0)