Commit 2651f2d0 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '207240-snippet-edit-filed-vue' into 'master'

Refactor Snippet Edit File field to Vue

See merge request gitlab-org/gitlab!26676
parents eedd57e7 35f1e7f4
<script>
import { initEditorLite } from '~/blob/utils';
export default {
props: {
value: {
type: String,
required: true,
},
fileName: {
type: String,
required: false,
default: '',
},
},
data() {
return {
content: this.value,
editor: null,
};
},
watch: {
fileName(newVal) {
this.editor.updateModelLanguage(newVal);
},
},
mounted() {
this.editor = initEditorLite({
el: this.$refs.editor,
blobPath: this.fileName,
blobContent: this.content,
});
},
methods: {
triggerFileChange() {
const val = this.editor.getValue();
this.content = val;
this.$emit('input', val);
},
},
};
</script>
<template>
<div class="file-content code">
<pre id="editor" ref="editor" data-editor-loading @focusout="triggerFileChange">{{
content
}}</pre>
</div>
</template>
/* global ace */
import Editor from '~/editor/editor_lite';
export function initEditorLite({ el, blobPath, blobContent }) {
if (!el) {
throw new Error(`"el" parameter is required to initialize Editor`);
}
let editor;
if (window?.gon?.features?.monacoSnippets) {
editor = new Editor();
editor.createInstance({
el,
blobPath,
blobContent,
});
} else {
editor = ace.edit(el);
}
return editor;
}
export default () => ({});
/* global ace */
import Editor from '~/editor/editor_lite';
import { initEditorLite } from '~/blob/utils';
import setupCollapsibleInputs from './collapsible_input';
let editor;
const initAce = () => {
editor = ace.edit('editor');
const editorEl = document.getElementById('editor');
const form = document.querySelector('.snippet-form-holder form');
const content = document.querySelector('.snippet-file-content');
editor = initEditorLite({ el: editorEl });
form.addEventListener('submit', () => {
content.value = editor.getValue();
});
......@@ -20,8 +21,7 @@ const initMonaco = () => {
const fileNameEl = document.querySelector('.js-snippet-file-name');
const form = document.querySelector('.snippet-form-holder form');
editor = new Editor();
editor.createInstance({
editor = initEditorLite({
el: editorEl,
blobPath: fileNameEl.value,
blobContent: contentEl.value,
......
<script>
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
import BlobContentEdit from '~/blob/components/blob_edit_content.vue';
export default {
components: {
BlobHeaderEdit,
BlobContentEdit,
},
props: {
content: {
type: String,
required: true,
},
fileName: {
type: String,
required: true,
},
},
data() {
return {
name: this.fileName,
blobContent: this.content,
};
},
};
</script>
<template>
<div class="form-group file-editor">
<label>{{ s__('Snippets|File') }}</label>
<div class="file-holder snippet">
<blob-header-edit v-model="name" />
<blob-content-edit v-model="blobContent" :file-name="name" />
</div>
</div>
</template>
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Blob Header Editing rendering matches the snapshot 1`] = `
<div
class="file-content code"
>
<pre
data-editor-loading=""
id="editor"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</pre>
</div>
`;
import { shallowMount } from '@vue/test-utils';
import BlobEditContent from '~/blob/components/blob_edit_content.vue';
import { initEditorLite } from '~/blob/utils';
import { nextTick } from 'vue';
jest.mock('~/blob/utils', () => ({
initEditorLite: jest.fn(),
}));
describe('Blob Header Editing', () => {
let wrapper;
const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
const fileName = 'lorem.txt';
function createComponent() {
wrapper = shallowMount(BlobEditContent, {
propsData: {
value,
fileName,
},
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('rendering', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders content', () => {
expect(wrapper.text()).toContain(value);
});
});
describe('functionality', () => {
it('initialises Editor Lite', () => {
const el = wrapper.find({ ref: 'editor' }).element;
expect(initEditorLite).toHaveBeenCalledWith({
el,
blobPath: fileName,
blobContent: value,
});
});
it('reacts to the changes in fileName', () => {
wrapper.vm.editor = {
updateModelLanguage: jest.fn(),
};
const newFileName = 'ipsum.txt';
wrapper.setProps({
fileName: newFileName,
});
return nextTick().then(() => {
expect(wrapper.vm.editor.updateModelLanguage).toHaveBeenCalledWith(newFileName);
});
});
it('emits input event when the blob content is changed', () => {
const editorEl = wrapper.find({ ref: 'editor' });
wrapper.vm.editor = {
getValue: jest.fn().mockReturnValue(value),
};
editorEl.trigger('focusout');
return nextTick().then(() => {
expect(wrapper.emitted().input[0]).toEqual([value]);
});
});
});
});
import Editor from '~/editor/editor_lite';
import * as utils from '~/blob/utils';
const mockCreateMonacoInstance = jest.fn();
jest.mock('~/editor/editor_lite', () => {
return jest.fn().mockImplementation(() => {
return { createInstance: mockCreateMonacoInstance };
});
});
const mockCreateAceInstance = jest.fn();
global.ace = {
edit: mockCreateAceInstance,
};
describe('Blob utilities', () => {
beforeEach(() => {
Editor.mockClear();
});
describe('initEditorLite', () => {
let editorEl;
const blobPath = 'foo.txt';
const blobContent = 'Foo bar';
beforeEach(() => {
setFixtures('<div id="editor"></div>');
editorEl = document.getElementById('editor');
});
describe('Monaco editor', () => {
let origProp;
beforeEach(() => {
origProp = window.gon;
window.gon = {
features: {
monacoSnippets: true,
},
};
});
afterEach(() => {
window.gon = origProp;
});
it('initializes the Editor Lite', () => {
utils.initEditorLite({ el: editorEl });
expect(Editor).toHaveBeenCalled();
});
it('creates the instance with the passed parameters', () => {
utils.initEditorLite({ el: editorEl });
expect(mockCreateMonacoInstance.mock.calls[0]).toEqual([
{
el: editorEl,
blobPath: undefined,
blobContent: undefined,
},
]);
utils.initEditorLite({ el: editorEl, blobPath, blobContent });
expect(mockCreateMonacoInstance.mock.calls[1]).toEqual([
{
el: editorEl,
blobPath,
blobContent,
},
]);
});
});
describe('ACE editor', () => {
let origProp;
beforeEach(() => {
origProp = window.gon;
window.gon = {
features: {
monacoSnippets: false,
},
};
});
afterEach(() => {
window.gon = origProp;
});
it('does not initialize the Editor Lite', () => {
utils.initEditorLite({ el: editorEl });
expect(Editor).not.toHaveBeenCalled();
expect(mockCreateAceInstance).toHaveBeenCalledWith(editorEl);
});
});
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Snippet Blob Edit component rendering matches the snapshot 1`] = `
<div
class="form-group file-editor"
>
<label>
File
</label>
<div
class="file-holder snippet"
>
<blob-header-edit-stub
value="lorem.txt"
/>
<blob-content-edit-stub
filename="lorem.txt"
value="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
/>
</div>
</div>
`;
import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
import BlobContentEdit from '~/blob/components/blob_edit_content.vue';
import { shallowMount } from '@vue/test-utils';
jest.mock('~/blob/utils', () => jest.fn());
describe('Snippet Blob Edit component', () => {
let wrapper;
const content = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
const fileName = 'lorem.txt';
function createComponent() {
wrapper = shallowMount(SnippetBlobEdit, {
propsData: {
content,
fileName,
},
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('rendering', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders required components', () => {
expect(wrapper.contains(BlobHeaderEdit)).toBe(true);
expect(wrapper.contains(BlobContentEdit)).toBe(true);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment