210 lines
8.2 KiB
JavaScript
210 lines
8.2 KiB
JavaScript
import MockAdapter from 'axios-mock-adapter';
|
|
import { Range, Position } from 'monaco-editor';
|
|
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
|
import { EditorMarkdownExtension } from '~/editor/extensions/source_editor_markdown_ext';
|
|
import SourceEditor from '~/editor/source_editor';
|
|
import axios from '~/lib/utils/axios_utils';
|
|
|
|
describe('Markdown Extension for Source Editor', () => {
|
|
let editor;
|
|
let instance;
|
|
let editorEl;
|
|
let mockAxios;
|
|
const firstLine = 'This is a';
|
|
const secondLine = 'multiline';
|
|
const thirdLine = 'string with some **markup**';
|
|
const text = `${firstLine}\n${secondLine}\n${thirdLine}`;
|
|
const markdownPath = 'foo.md';
|
|
|
|
const setSelection = (startLineNumber = 1, startColumn = 1, endLineNumber = 1, endColumn = 1) => {
|
|
const selection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);
|
|
instance.setSelection(selection);
|
|
};
|
|
const selectSecondString = () => setSelection(2, 1, 2, secondLine.length + 1); // select the whole second line
|
|
const selectSecondAndThirdLines = () => setSelection(2, 1, 3, thirdLine.length + 1); // select second and third lines
|
|
|
|
const selectionToString = () => instance.getSelection().toString();
|
|
const positionToString = () => instance.getPosition().toString();
|
|
|
|
beforeEach(() => {
|
|
mockAxios = new MockAdapter(axios);
|
|
setHTMLFixture('<div id="editor" data-editor-loading></div>');
|
|
editorEl = document.getElementById('editor');
|
|
editor = new SourceEditor();
|
|
instance = editor.createInstance({
|
|
el: editorEl,
|
|
blobPath: markdownPath,
|
|
blobContent: text,
|
|
});
|
|
instance.use({ definition: EditorMarkdownExtension });
|
|
});
|
|
|
|
afterEach(() => {
|
|
instance.dispose();
|
|
editorEl.remove();
|
|
mockAxios.restore();
|
|
|
|
resetHTMLFixture();
|
|
});
|
|
|
|
describe('getSelectedText', () => {
|
|
it('does not fail if there is no selection and returns the empty string', () => {
|
|
jest.spyOn(instance, 'getSelection');
|
|
const resText = instance.getSelectedText();
|
|
|
|
expect(instance.getSelection).toHaveBeenCalled();
|
|
expect(resText).toBe('');
|
|
});
|
|
|
|
it.each`
|
|
description | selection | expectedString
|
|
${'same-line'} | ${[1, 1, 1, firstLine.length + 1]} | ${firstLine}
|
|
${'two-lines'} | ${[1, 1, 2, secondLine.length + 1]} | ${`${firstLine}\n${secondLine}`}
|
|
${'multi-lines'} | ${[1, 1, 3, thirdLine.length + 1]} | ${text}
|
|
`('correctly returns selected text for $description', ({ selection, expectedString }) => {
|
|
setSelection(...selection);
|
|
|
|
const resText = instance.getSelectedText();
|
|
|
|
expect(resText).toBe(expectedString);
|
|
});
|
|
|
|
it('accepts selection object that serves as a source instead of current selection', () => {
|
|
selectSecondString();
|
|
const firstLineSelection = new Range(1, 1, 1, firstLine.length + 1);
|
|
|
|
const resText = instance.getSelectedText(firstLineSelection);
|
|
|
|
expect(resText).toBe(firstLine);
|
|
});
|
|
});
|
|
|
|
describe('replaceSelectedText', () => {
|
|
const expectedStr = 'foo';
|
|
|
|
it('replaces selected text with the supplied one', () => {
|
|
selectSecondString();
|
|
instance.replaceSelectedText(expectedStr);
|
|
|
|
expect(instance.getValue()).toBe(`${firstLine}\n${expectedStr}\n${thirdLine}`);
|
|
});
|
|
|
|
it('prepends the supplied text if no text is selected', () => {
|
|
instance.replaceSelectedText(expectedStr);
|
|
expect(instance.getValue()).toBe(`${expectedStr}${firstLine}\n${secondLine}\n${thirdLine}`);
|
|
});
|
|
|
|
it('replaces selection with empty string if no text is supplied', () => {
|
|
selectSecondString();
|
|
instance.replaceSelectedText();
|
|
expect(instance.getValue()).toBe(`${firstLine}\n\n${thirdLine}`);
|
|
});
|
|
|
|
it('puts cursor at the end of the new string and collapses selection by default', () => {
|
|
selectSecondString();
|
|
instance.replaceSelectedText(expectedStr);
|
|
|
|
expect(positionToString()).toBe(`(2,${expectedStr.length + 1})`);
|
|
expect(selectionToString()).toBe(
|
|
`[2,${expectedStr.length + 1} -> 2,${expectedStr.length + 1}]`,
|
|
);
|
|
});
|
|
|
|
it('puts cursor at the end of the new string and keeps selection if "select" is supplied', () => {
|
|
const select = 'url';
|
|
const complexReplacementString = `[${secondLine}](${select})`;
|
|
selectSecondString();
|
|
instance.replaceSelectedText(complexReplacementString, select);
|
|
|
|
expect(positionToString()).toBe(`(2,${complexReplacementString.length + 1})`);
|
|
expect(selectionToString()).toBe(`[2,1 -> 2,${complexReplacementString.length + 1}]`);
|
|
});
|
|
});
|
|
|
|
describe('moveCursor', () => {
|
|
const setPosition = (endCol) => {
|
|
const currentPos = new Position(2, endCol);
|
|
instance.setPosition(currentPos);
|
|
};
|
|
|
|
it.each`
|
|
direction | condition | startColumn | shift | endPosition
|
|
${'left'} | ${'negative'} | ${secondLine.length + 1} | ${-1} | ${`(2,${secondLine.length})`}
|
|
${'left'} | ${'negative'} | ${secondLine.length} | ${secondLine.length * -1} | ${'(2,1)'}
|
|
${'right'} | ${'positive'} | ${1} | ${1} | ${'(2,2)'}
|
|
${'right'} | ${'positive'} | ${2} | ${secondLine.length} | ${`(2,${secondLine.length + 1})`}
|
|
${'up'} | ${'positive'} | ${1} | ${[0, -1]} | ${'(1,1)'}
|
|
${'top of file'} | ${'positive'} | ${1} | ${[0, -100]} | ${'(1,1)'}
|
|
${'down'} | ${'negative'} | ${1} | ${[0, 1]} | ${'(3,1)'}
|
|
${'end of file'} | ${'negative'} | ${1} | ${[0, 100]} | ${`(3,${thirdLine.length + 1})`}
|
|
${'end of line'} | ${'too large'} | ${1} | ${secondLine.length + 100} | ${`(2,${secondLine.length + 1})`}
|
|
${'start of line'} | ${'too low'} | ${1} | ${-100} | ${'(2,1)'}
|
|
`(
|
|
'moves cursor to the $direction if $condition supplied',
|
|
({ startColumn, shift, endPosition }) => {
|
|
setPosition(startColumn);
|
|
if (Array.isArray(shift)) {
|
|
instance.moveCursor(...shift);
|
|
} else {
|
|
instance.moveCursor(shift);
|
|
}
|
|
expect(positionToString()).toBe(endPosition);
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('selectWithinSelection', () => {
|
|
it('scopes down current selection to supplied text', () => {
|
|
const selectedText = `${secondLine}\n${thirdLine}`;
|
|
const toSelect = 'string';
|
|
selectSecondAndThirdLines();
|
|
|
|
expect(selectionToString()).toBe(`[2,1 -> 3,${thirdLine.length + 1}]`);
|
|
|
|
instance.selectWithinSelection(toSelect, selectedText);
|
|
expect(selectionToString()).toBe(`[3,1 -> 3,${toSelect.length + 1}]`);
|
|
});
|
|
|
|
it('does not fail when only `toSelect` is supplied and fetches the text from selection', () => {
|
|
const toSelect = 'string';
|
|
selectSecondAndThirdLines();
|
|
|
|
instance.selectWithinSelection(toSelect);
|
|
|
|
expect(selectionToString()).toBe(`[3,1 -> 3,${toSelect.length + 1}]`);
|
|
});
|
|
|
|
it('does nothing if no `toSelect` is supplied', () => {
|
|
selectSecondAndThirdLines();
|
|
const expectedPos = `(3,${thirdLine.length + 1})`;
|
|
const expectedSelection = `[2,1 -> 3,${thirdLine.length + 1}]`;
|
|
|
|
expect(positionToString()).toBe(expectedPos);
|
|
expect(selectionToString()).toBe(expectedSelection);
|
|
|
|
instance.selectWithinSelection();
|
|
|
|
expect(positionToString()).toBe(expectedPos);
|
|
expect(selectionToString()).toBe(expectedSelection);
|
|
});
|
|
|
|
it('does nothing if no selection is set in the editor', () => {
|
|
const expectedPos = '(1,1)';
|
|
const expectedSelection = '[1,1 -> 1,1]';
|
|
const toSelect = 'string';
|
|
|
|
expect(positionToString()).toBe(expectedPos);
|
|
expect(selectionToString()).toBe(expectedSelection);
|
|
|
|
instance.selectWithinSelection(toSelect);
|
|
|
|
expect(positionToString()).toBe(expectedPos);
|
|
expect(selectionToString()).toBe(expectedSelection);
|
|
|
|
instance.selectWithinSelection();
|
|
|
|
expect(positionToString()).toBe(expectedPos);
|
|
expect(selectionToString()).toBe(expectedSelection);
|
|
});
|
|
});
|
|
});
|