Commit 3e32fcab authored by Denys Mishunov's avatar Denys Mishunov

Set props and listener explicitely

To have props and listeners' assignemtn consistent in the component,
this branch sets value and listener on <blob-content-edit>
explicitely instead of implicitely via v-bind="$attrs" and
v-on="$listeners".

Allows the component to not have content passed to it by default
This is important for the cases when the component is used in
creation of a new snippet.
parent 97cf5659
......@@ -5,7 +5,8 @@ export default {
props: {
value: {
type: String,
required: true,
required: false,
default: '',
},
fileName: {
type: String,
......@@ -15,7 +16,6 @@ export default {
},
data() {
return {
content: this.value,
editor: null,
};
},
......@@ -28,14 +28,12 @@ export default {
this.editor = initEditorLite({
el: this.$refs.editor,
blobPath: this.fileName,
blobContent: this.content,
blobContent: this.value,
});
},
methods: {
triggerFileChange() {
const val = this.editor.getValue();
this.content = val;
this.$emit('input', val);
this.$emit('input', this.editor.getValue());
},
},
};
......@@ -43,7 +41,7 @@ export default {
<template>
<div class="file-content code">
<pre id="editor" ref="editor" data-editor-loading @focusout="triggerFileChange">{{
content
value
}}</pre>
</div>
</template>
<script>
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
import BlobContentEdit from '~/blob/components/blob_edit_content.vue';
import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
BlobHeaderEdit,
BlobContentEdit,
GlLoadingIcon,
},
inheritAttrs: false,
props: {
value: {
type: String,
required: false,
default: '',
},
fileName: {
type: String,
required: false,
default: '',
},
},
methods: {
emitFileNameChange(newFileName) {
this.$emit('name-change', newFileName);
isLoading: {
type: Boolean,
required: false,
default: true,
},
},
};
......@@ -26,8 +33,19 @@ export default {
<div class="form-group file-editor">
<label>{{ s__('Snippets|File') }}</label>
<div class="file-holder snippet">
<blob-header-edit :value="fileName" @input="emitFileNameChange" />
<blob-content-edit v-bind="$attrs" :file-name="fileName" v-on="$listeners" />
<blob-header-edit :value="fileName" @input="$emit('name-change', $event)" />
<gl-loading-icon
v-if="isLoading"
:label="__('Loading snippet')"
:size="2"
class="loading-animation prepend-top-20 append-bottom-20"
/>
<blob-content-edit
v-else
:value="value"
:file-name="fileName"
@input="$emit('input', $event)"
/>
</div>
</div>
</template>
......@@ -12,11 +12,12 @@ describe('Blob Header Editing', () => {
const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
const fileName = 'lorem.txt';
function createComponent() {
function createComponent(props = {}) {
wrapper = shallowMount(BlobEditContent, {
propsData: {
value,
fileName,
...props,
},
});
}
......@@ -40,6 +41,14 @@ describe('Blob Header Editing', () => {
});
describe('functionality', () => {
it('does not fail without content', () => {
const spy = jest.spyOn(global.console, 'error');
createComponent({ value: undefined });
expect(spy).not.toHaveBeenCalled();
expect(wrapper.contains('#editor')).toBe(true);
});
it('initialises Editor Lite', () => {
const el = wrapper.find({ ref: 'editor' }).element;
expect(initEditorLite).toHaveBeenCalledWith({
......
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 { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
......@@ -13,11 +14,13 @@ describe('Snippet Blob Edit component', () => {
const findHeader = () => wrapper.find(BlobHeaderEdit);
const findContent = () => wrapper.find(BlobContentEdit);
function createComponent() {
function createComponent(props = {}) {
wrapper = shallowMount(SnippetBlobEdit, {
propsData: {
value,
fileName,
isLoading: false,
...props,
},
});
}
......@@ -39,9 +42,23 @@ describe('Snippet Blob Edit component', () => {
expect(findHeader().exists()).toBe(true);
expect(findContent().exists()).toBe(true);
});
it('renders loader if isLoading equals true', () => {
createComponent({ isLoading: true });
expect(wrapper.contains(GlLoadingIcon)).toBe(true);
expect(findContent().exists()).toBe(false);
});
});
describe('functionality', () => {
it('does not fail without content', () => {
const spy = jest.spyOn(global.console, 'error');
createComponent({ value: undefined });
expect(spy).not.toHaveBeenCalled();
expect(findContent().exists()).toBe(true);
});
it('emits "name-change" event when the file name gets changed', () => {
expect(wrapper.emitted('name-change')).toBeUndefined();
const newFilename = 'foo.bar';
......@@ -51,5 +68,15 @@ describe('Snippet Blob Edit component', () => {
expect(wrapper.emitted('name-change')[0]).toEqual([newFilename]);
});
});
it('emits "input" event when the file content gets changed', () => {
expect(wrapper.emitted('input')).toBeUndefined();
const newValue = 'foo.bar';
findContent().vm.$emit('input', newValue);
return nextTick().then(() => {
expect(wrapper.emitted('input')[0]).toEqual([newValue]);
});
});
});
});
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