Skip to content

Commit ac9dbc1

Browse files
committed
Fix editor
1 parent 080969b commit ac9dbc1

2 files changed

Lines changed: 67 additions & 26 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { act, renderHook } from '@testing-library/react';
2+
3+
import useEditor from '../widgets/utils/useEditor';
4+
5+
vi.mock('../widgets/utils/useCursorUpdates', () => ({ default: () => {} }));
6+
vi.mock('../widgets/utils/useEditorCursor', () => ({ default: () => {} }));
7+
vi.mock('../widgets/utils/useResizeListener', () => ({ default: () => {} }));
8+
9+
describe('useEditor', () => {
10+
it('uses the latest code check callback for Ctrl+Enter', () => {
11+
const actions: Array<{ id: string; run: () => void }> = [];
12+
const domNode = document.createElement('div');
13+
const editor = {
14+
addAction: vi.fn((action) => actions.push(action)),
15+
focus: vi.fn(),
16+
getDomNode: () => domNode,
17+
getOptions: () => ({ readOnly: false }),
18+
onDidChangeModelContent: vi.fn(),
19+
updateOptions: vi.fn(),
20+
};
21+
const monaco = {
22+
editor: { defineTheme: vi.fn() },
23+
KeyCode: { Enter: 3, KEY_M: 4 },
24+
KeyMod: { CtrlCmd: 1 },
25+
};
26+
const checkResult = vi.fn();
27+
28+
const { result, rerender } = renderHook(
29+
({ onCheck }: { onCheck?: () => void }) =>
30+
useEditor({
31+
allowClipboard: true,
32+
checkResult: onCheck,
33+
editable: true,
34+
}),
35+
{ initialProps: { onCheck: undefined as (() => void) | undefined } },
36+
);
37+
38+
act(() => result.current.handleEditorDidMount(editor, monaco));
39+
rerender({ onCheck: checkResult });
40+
41+
const checkAction = actions.find(({ id }) => id === 'codebattle-check-keys');
42+
act(() => checkAction?.run());
43+
44+
expect(checkAction).toBeDefined();
45+
expect(checkResult).toHaveBeenCalledOnce();
46+
});
47+
});

‎apps/codebattle/assets/js/widgets/utils/useEditor.ts‎

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ const useEditor = (props: UseEditorProps) => {
145145
const [editor, setEditor] = useState();
146146
const [monaco, setMonaco] = useState();
147147

148+
// Monaco registers keybindings only when the editor mounts. Keep the callback
149+
// current when the game becomes active without recreating the editor action.
150+
const checkResultRef = useRef(props.checkResult);
151+
useEffect(() => {
152+
checkResultRef.current = props.checkResult;
153+
}, [props.checkResult]);
154+
148155
// Keep the latest onTelemetryEvent in a ref so Monaco's mount-time listener
149156
// closure always invokes the current callback, not a stale (no-op) snapshot
150157
// captured before the gating state turned on.
@@ -199,15 +206,7 @@ const useEditor = (props: UseEditorProps) => {
199206

200207
// currentMonaco.editor.setTheme('code-theme-dark');
201208

202-
const {
203-
editable,
204-
roomMode,
205-
checkResult,
206-
toggleMuteSound,
207-
syntax,
208-
gameStartTimeMs,
209-
allowClipboard,
210-
} = props;
209+
const { editable, roomMode, toggleMuteSound, syntax, gameStartTimeMs, allowClipboard } = props;
211210

212211
// eslint-disable-next-line @typescript-eslint/no-explicit-any
213212
const emitTelemetry = (payload: Record<string, any>) => {
@@ -414,23 +413,18 @@ const useEditor = (props: UseEditorProps) => {
414413
}
415414

416415
// Codebattle action: Check on Ctrl+Enter
417-
if (checkResult) {
418-
currentEditor.addAction({
419-
id: 'codebattle-check-keys',
420-
label: 'Codebattle check start',
421-
keybindings: [currentMonaco.KeyMod.CtrlCmd | currentMonaco.KeyCode.Enter],
422-
run: () => {
423-
if (!currentEditor.getOptions().readOnly) {
424-
checkResult();
425-
}
426-
},
427-
});
428-
} else {
429-
currentEditor.addCommand(
430-
currentMonaco.KeyMod.CtrlCmd | currentMonaco.KeyCode.Enter,
431-
() => null,
432-
);
433-
}
416+
currentEditor.addAction({
417+
id: 'codebattle-check-keys',
418+
label: 'Codebattle check start',
419+
keybindings: [currentMonaco.KeyMod.CtrlCmd | currentMonaco.KeyCode.Enter],
420+
run: () => {
421+
const currentCheckResult = checkResultRef.current;
422+
423+
if (!currentEditor.getOptions().readOnly && currentCheckResult) {
424+
currentCheckResult();
425+
}
426+
},
427+
});
434428

435429
// Codebattle action: toggle sound on Ctrl+M
436430
currentEditor.addAction({

0 commit comments

Comments
 (0)