From a2021bc8ec8f64f330cc2bb34e31eb03a04eca35 Mon Sep 17 00:00:00 2001 From: Veeresh Date: Mon, 10 Aug 2026 14:46:50 +0530 Subject: [PATCH] fix(diff-editor): support originalEditable in inline diff mode (#5302) --- test/diffEditor.test.ts | 117 ++++++++++++++++++++++++++++++++++++++++ test/test-setup.mjs | 18 +++++++ 2 files changed, 135 insertions(+) create mode 100644 test/diffEditor.test.ts diff --git a/test/diffEditor.test.ts b/test/diffEditor.test.ts new file mode 100644 index 0000000000..1c546a57ed --- /dev/null +++ b/test/diffEditor.test.ts @@ -0,0 +1,117 @@ +import test from 'node:test'; +import assert from 'node:assert'; +import * as monaco from '../node_modules/monaco-editor-core/esm/vs/editor/editor.api.js'; + +test('diff editor originalEditable option in inline mode (issue #5302)', async (t) => { + await t.test('allows editing original model when originalEditable is true and readOnly is false in inline diff mode', () => { + const originalModel = monaco.editor.createModel('original content', 'text/plain'); + const modifiedModel = monaco.editor.createModel('modified content', 'text/plain'); + const container = document.createElement('div'); + document.body.appendChild(container); + + const diffEditor = monaco.editor.createDiffEditor(container, { + renderSideBySide: false, + originalEditable: true, + readOnly: false, + renderOverviewRuler: false, + }); + + diffEditor.setModel({ original: originalModel, modified: modifiedModel }); + + const origEditor = diffEditor.getOriginalEditor(); + const modEditor = diffEditor.getModifiedEditor(); + + assert.strictEqual(origEditor.getOption(monaco.editor.EditorOption.readOnly), false); + assert.strictEqual(modEditor.getOption(monaco.editor.EditorOption.readOnly), false); + + // Verify editing original model applies changes + const editSuccess = origEditor.executeEdits('test', [{ + range: new monaco.Range(1, 1, 1, 1), + text: 'prefix ' + }]); + assert.strictEqual(editSuccess, true); + assert.strictEqual(originalModel.getValue(), 'prefix original content'); + + diffEditor.dispose(); + originalModel.dispose(); + modifiedModel.dispose(); + }); + + await t.test('respects readOnly: true even when originalEditable: true in inline diff mode', () => { + const originalModel = monaco.editor.createModel('original content', 'text/plain'); + const modifiedModel = monaco.editor.createModel('modified content', 'text/plain'); + const container = document.createElement('div'); + document.body.appendChild(container); + + const diffEditor = monaco.editor.createDiffEditor(container, { + renderSideBySide: false, + originalEditable: true, + readOnly: true, + renderOverviewRuler: false, + }); + + diffEditor.setModel({ original: originalModel, modified: modifiedModel }); + + const origEditor = diffEditor.getOriginalEditor(); + const modEditor = diffEditor.getModifiedEditor(); + + assert.strictEqual(origEditor.getOption(monaco.editor.EditorOption.readOnly), true); + assert.strictEqual(modEditor.getOption(monaco.editor.EditorOption.readOnly), true); + + diffEditor.dispose(); + originalModel.dispose(); + modifiedModel.dispose(); + }); + + await t.test('respects readOnly: false and originalEditable: false in inline diff mode', () => { + const originalModel = monaco.editor.createModel('original content', 'text/plain'); + const modifiedModel = monaco.editor.createModel('modified content', 'text/plain'); + const container = document.createElement('div'); + document.body.appendChild(container); + + const diffEditor = monaco.editor.createDiffEditor(container, { + renderSideBySide: false, + originalEditable: false, + readOnly: false, + renderOverviewRuler: false, + }); + + diffEditor.setModel({ original: originalModel, modified: modifiedModel }); + + const origEditor = diffEditor.getOriginalEditor(); + const modEditor = diffEditor.getModifiedEditor(); + + assert.strictEqual(origEditor.getOption(monaco.editor.EditorOption.readOnly), true); + assert.strictEqual(modEditor.getOption(monaco.editor.EditorOption.readOnly), false); + + diffEditor.dispose(); + originalModel.dispose(); + modifiedModel.dispose(); + }); + + await t.test('preserves side-by-side behavior for originalEditable and readOnly options', () => { + const originalModel = monaco.editor.createModel('original content', 'text/plain'); + const modifiedModel = monaco.editor.createModel('modified content', 'text/plain'); + const container = document.createElement('div'); + document.body.appendChild(container); + + const diffEditor = monaco.editor.createDiffEditor(container, { + renderSideBySide: true, + originalEditable: true, + readOnly: false, + renderOverviewRuler: false, + }); + + diffEditor.setModel({ original: originalModel, modified: modifiedModel }); + + const origEditor = diffEditor.getOriginalEditor(); + const modEditor = diffEditor.getModifiedEditor(); + + assert.strictEqual(origEditor.getOption(monaco.editor.EditorOption.readOnly), false); + assert.strictEqual(modEditor.getOption(monaco.editor.EditorOption.readOnly), false); + + diffEditor.dispose(); + originalModel.dispose(); + modifiedModel.dispose(); + }); +}); diff --git a/test/test-setup.mjs b/test/test-setup.mjs index 75f0e1c569..808e1770d3 100644 --- a/test/test-setup.mjs +++ b/test/test-setup.mjs @@ -6,6 +6,20 @@ import { createRequire } from 'module'; import { JSDOM } from 'jsdom'; +import { register } from 'node:module'; + +try { + register(`data:text/javascript, +export async function load(url, context, nextLoad) { + if (url.endsWith('.css')) { + return { format: 'module', shortCircuit: true, source: 'export default {};' }; + } + return nextLoad(url, context); +}`, import.meta.url); +} catch (e) { + // fallback if register is not available +} + // Handle CSS imports from monaco-editor-core in CJS require context const require = createRequire(import.meta.url); require.extensions['.css'] = function (module, filename) { @@ -20,6 +34,8 @@ const dom = new JSDOM('', { global.window = dom.window; global.document = dom.window.document; +global.document.queryCommandSupported = () => false; +global.document.execCommand = () => false; Object.defineProperty(global, 'navigator', { value: dom.window.navigator, writable: true, configurable: true }); global.HTMLElement = dom.window.HTMLElement; global.Node = dom.window.Node; @@ -27,6 +43,8 @@ global.Element = dom.window.Element; global.Event = dom.window.Event; global.MouseEvent = dom.window.MouseEvent; global.KeyboardEvent = dom.window.KeyboardEvent; +global.UIEvent = dom.window.UIEvent; +global.ResizeObserver = class { observe() {} unobserve() {} disconnect() {} }; global.customElements = dom.window.customElements; global.CSS = {