blob: 4aa1fd7fb3ace5cf26cb73986966765324d59616 [file]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../test/test-setup';
import './codemirror-element';
import {assert, fixture, html} from '@open-wc/testing';
import {CodeMirrorElement} from './codemirror-element';
suite('codemirror-element tests', () => {
let element: CodeMirrorElement;
setup(async () => {
element = await fixture<CodeMirrorElement>(
html`<codemirror-element></codemirror-element>`,
);
element.lineNum = 123;
element.prefs = {
match_brackets: true,
};
await element.updateComplete;
});
test('render', () => {
assert.shadowDom.equal(
element,
/* HTML */ `
<div id="wrapper">
<div class="cm-editor ͼ1 ͼ1f ͼ1g ͼ1h ͼ1i ͼ2 ͼ4">
<div aria-live="polite" class="cm-announced"></div>
<div class="cm-scroller" tabindex="-1">
<div
aria-hidden="true"
class="cm-gutters cm-gutters-before"
style="min-height: 14px; position: sticky;"
>
<div class="cm-gutter cm-lineNumbers">
<div
class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;"
>
9
</div>
<div
class="cm-activeLineGutter cm-gutterElement"
style="height: 14px;"
>
1
</div>
</div>
<div class="cm-foldGutter cm-gutter">
<div
class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;"
>
<span title="Unfold line"> › </span>
</div>
<div
class="cm-activeLineGutter cm-gutterElement"
style="height: 14px;"
></div>
</div>
</div>
<div
aria-multiline="true"
autocapitalize="off"
autocorrect="off"
class="cm-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="tab-size: 0;"
translate="no"
writingsuggestions="false"
>
<div class="cm-line">
<br />
</div>
</div>
<div
aria-hidden="true"
class="cm-cursorLayer cm-layer cm-layer-above"
style="z-index: 150; animation-duration: 1200ms;"
></div>
<div
aria-hidden="true"
class="cm-layer cm-selectionLayer"
style="z-index: -2;"
></div>
</div>
</div>
</div>
<div class="statusLine">
<div class="cursorPosition">
<span id="result"> Line: 1, Column: 1 </span>
</div>
</div>
`,
);
});
async function waitForEditorInstance(
el: CodeMirrorElement,
attempts = 20,
delayMs = 50,
) {
for (let i = 0; i < attempts && !el.editor; i++) {
await new Promise<void>(resolve => {
setTimeout((): void => resolve(), delayMs);
});
}
return el.editor;
}
function waitForContentChangeEvent(el: CodeMirrorElement) {
return new Promise<CustomEvent<{value: string}>>(resolve => {
el.addEventListener(
'content-change',
(e: Event): void => {
resolve(e as CustomEvent<{value: string}>);
},
{once: true},
);
});
}
test('dispatches content-change event when editor content changes', async () => {
const initialContent = 'first line\nsecond line\n';
const editorElement = await fixture<CodeMirrorElement>(
html`
<codemirror-element .fileContent=${initialContent}></codemirror-element>
`,
);
await editorElement.updateComplete;
const editorView = await waitForEditorInstance(editorElement);
assert.isOk(editorView);
const eventPromise = waitForContentChangeEvent(editorElement);
void editorView.dispatch({
changes: {
from: 0,
to: 0,
insert: 'X',
},
});
const event = await eventPromise;
assert.isString(event.detail.value);
assert.isTrue(event.detail.value.length > initialContent.length);
});
test('content-change preserves LF for LF-only inputs', async () => {
const editorElement = await fixture<CodeMirrorElement>(
html`
<codemirror-element .fileContent=${'a\nb\n'}></codemirror-element>
`,
);
await editorElement.updateComplete;
const editorView = await waitForEditorInstance(editorElement);
assert.isOk(editorView);
const eventPromise = waitForContentChangeEvent(editorElement);
void editorView.dispatch({
changes: {
from: 0,
to: 0,
insert: 'x',
},
});
const event = await eventPromise;
assert.isFalse(/\r\n/.test(event.detail.value));
assert.isTrue(event.detail.value.endsWith('\n'));
});
test('content-change preserves CRLF for CRLF inputs', async () => {
const editorElement = await fixture<CodeMirrorElement>(
html`
<codemirror-element .fileContent=${'a\r\nb\r\n'}></codemirror-element>
`,
);
await editorElement.updateComplete;
const editorView = await waitForEditorInstance(editorElement);
assert.isOk(editorView);
const eventPromise = waitForContentChangeEvent(editorElement);
void editorView.dispatch({
changes: {
from: 0,
to: 0,
insert: 'x',
},
});
const event = await eventPromise;
assert.isString(event.detail.value);
assert.isTrue(/\r\n/.test(event.detail.value));
assert.isTrue(event.detail.value.endsWith('\r\n'));
});
});