summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/repo/components/new_dropdown/index.vue1
-rw-r--r--app/assets/javascripts/repo/index.js1
-rw-r--r--app/assets/javascripts/repo/stores/repo_store.js1
-rw-r--r--app/views/shared/repo/_repo.html.haml3
-rw-r--r--spec/javascripts/helpers/vue_mount_component_helper.js5
-rw-r--r--spec/javascripts/repo/components/new_dropdown/index_spec.js63
-rw-r--r--spec/javascripts/repo/components/new_dropdown/modal_spec.js180
7 files changed, 250 insertions, 4 deletions
diff --git a/app/assets/javascripts/repo/components/new_dropdown/index.vue b/app/assets/javascripts/repo/components/new_dropdown/index.vue
index 864db679e82..53baa02c344 100644
--- a/app/assets/javascripts/repo/components/new_dropdown/index.vue
+++ b/app/assets/javascripts/repo/components/new_dropdown/index.vue
@@ -31,6 +31,7 @@
type="button"
class="btn btn-default dropdown-toggle add-to-tree"
data-toggle="dropdown"
+ aria-label="Create new file or directory"
>
<i
class="fa fa-plus"
diff --git a/app/assets/javascripts/repo/index.js b/app/assets/javascripts/repo/index.js
index b1b40d8b8cc..3586b5fea67 100644
--- a/app/assets/javascripts/repo/index.js
+++ b/app/assets/javascripts/repo/index.js
@@ -28,6 +28,7 @@ function setInitialStore(data) {
Store.service = Service;
Store.service.url = data.url;
Store.service.refsUrl = data.refsUrl;
+ Store.path = data.currentPath;
Store.projectId = data.projectId;
Store.projectName = data.projectName;
Store.projectUrl = data.projectUrl;
diff --git a/app/assets/javascripts/repo/stores/repo_store.js b/app/assets/javascripts/repo/stores/repo_store.js
index f4ab80b2c98..530c725ceb6 100644
--- a/app/assets/javascripts/repo/stores/repo_store.js
+++ b/app/assets/javascripts/repo/stores/repo_store.js
@@ -38,6 +38,7 @@ const RepoStore = {
newMrTemplateUrl: '',
branchChanged: false,
commitMessage: '',
+ path: '',
loading: {
tree: false,
blob: false,
diff --git a/app/views/shared/repo/_repo.html.haml b/app/views/shared/repo/_repo.html.haml
index 7185f5bcc5b..7861f92b33f 100644
--- a/app/views/shared/repo/_repo.html.haml
+++ b/app/views/shared/repo/_repo.html.haml
@@ -7,4 +7,5 @@
blob_url: namespace_project_blob_path(project.namespace, project, '{{branch}}'),
new_mr_template_url: namespace_project_new_merge_request_path(project.namespace, project, merge_request: { source_branch: '{{source_branch}}' }),
can_commit: (!!can_push_branch?(project, @ref)).to_s,
- on_top_of_branch: (!!on_top_of_branch?(project, @ref)).to_s } }
+ on_top_of_branch: (!!on_top_of_branch?(project, @ref)).to_s,
+ current_path: @path } }
diff --git a/spec/javascripts/helpers/vue_mount_component_helper.js b/spec/javascripts/helpers/vue_mount_component_helper.js
index d7a2e86771c..b71136c4114 100644
--- a/spec/javascripts/helpers/vue_mount_component_helper.js
+++ b/spec/javascripts/helpers/vue_mount_component_helper.js
@@ -1,4 +1,3 @@
-export default (Component, props = {}) => new Component({
+export default (Component, props = {}, el = null) => new Component({
propsData: props,
-}).$mount();
-
+}).$mount(el);
diff --git a/spec/javascripts/repo/components/new_dropdown/index_spec.js b/spec/javascripts/repo/components/new_dropdown/index_spec.js
new file mode 100644
index 00000000000..884d065718b
--- /dev/null
+++ b/spec/javascripts/repo/components/new_dropdown/index_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import newDropdown from '~/repo/components/new_dropdown/index.vue';
+import createComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('new dropdown component', () => {
+ let vm;
+
+ beforeEach(() => {
+ const component = Vue.extend(newDropdown);
+
+ vm = createComponent(component);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders new file and new directory links', () => {
+ expect(vm.$el.querySelectorAll('a')[0].textContent.trim()).toBe('New file');
+ expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe('New directory');
+ });
+
+ describe('createNewItem', () => {
+ it('sets modalType to blob when new file is clicked', () => {
+ vm.$el.querySelectorAll('a')[0].click();
+
+ expect(vm.modalType).toBe('blob');
+ });
+
+ it('sets modalType to tree when new directory is clicked', () => {
+ vm.$el.querySelectorAll('a')[1].click();
+
+ expect(vm.modalType).toBe('tree');
+ });
+
+ it('opens modal when link is clicked', (done) => {
+ vm.$el.querySelectorAll('a')[0].click();
+
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.modal')).not.toBeNull();
+
+ done();
+ });
+ });
+ });
+
+ describe('toggleModalOpen', () => {
+ it('closes modal after toggling', (done) => {
+ vm.toggleModalOpen();
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.modal')).not.toBeNull();
+ })
+ .then(vm.toggleModalOpen)
+ .then(() => {
+ expect(vm.$el.querySelector('.modal')).toBeNull();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/repo/components/new_dropdown/modal_spec.js b/spec/javascripts/repo/components/new_dropdown/modal_spec.js
new file mode 100644
index 00000000000..4be92e9d944
--- /dev/null
+++ b/spec/javascripts/repo/components/new_dropdown/modal_spec.js
@@ -0,0 +1,180 @@
+import Vue from 'vue';
+import RepoStore from '~/repo/stores/repo_store';
+import RepoHelper from '~/repo/helpers/repo_helper';
+import modal from '~/repo/components/new_dropdown/modal.vue';
+import createComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('new file modal component', () => {
+ const Component = Vue.extend(modal);
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+
+ RepoStore.files = [];
+ RepoStore.openedFiles = [];
+ RepoStore.setViewToPreview();
+ });
+
+ ['tree', 'blob'].forEach((type) => {
+ describe(type, () => {
+ beforeEach(() => {
+ vm = createComponent(Component, {
+ type,
+ });
+ });
+
+ it(`sets modal title as ${type}`, () => {
+ const title = type === 'tree' ? 'directory' : 'file';
+
+ expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`);
+ });
+
+ it(`sets button label as ${type}`, () => {
+ const title = type === 'tree' ? 'directory' : 'file';
+
+ expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`);
+ });
+
+ it(`sets form label as ${type}`, () => {
+ const title = type === 'tree' ? 'Directory' : 'File';
+
+ expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe(`${title} name`);
+ });
+
+ it('emits toggle event after creating file', () => {
+ spyOn(vm, '$emit');
+
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(vm.$emit).toHaveBeenCalledWith('toggle');
+ });
+
+ it('sets editMode to true', () => {
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.editMode).toBeTruthy();
+ });
+
+ it('toggles blob view', () => {
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.isPreviewView()).toBeFalsy();
+ });
+
+ it('adds file into activeFiles', () => {
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.openedFiles.length).toBe(1);
+ });
+ });
+ });
+
+ describe('file', () => {
+ beforeEach(() => {
+ vm = createComponent(Component, {
+ type: 'blob',
+ });
+ });
+
+ it('creates new file', () => {
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('testing');
+ expect(RepoStore.files[0].type).toBe('blob');
+ expect(RepoStore.files[0].tempFile).toBeTruthy();
+ });
+
+ it('does not create temp file when file already exists', () => {
+ RepoStore.files.push(RepoHelper.serializeRepoEntity('blob', {
+ name: 'testing',
+ }));
+
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('testing');
+ expect(RepoStore.files[0].type).toBe('blob');
+ expect(RepoStore.files[0].tempFile).toBeUndefined();
+ });
+ });
+
+ describe('tree', () => {
+ beforeEach(() => {
+ vm = createComponent(Component, {
+ type: 'tree',
+ });
+ });
+
+ it('creates new tree', () => {
+ vm.entryName = 'testing';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('testing');
+ expect(RepoStore.files[0].type).toBe('tree');
+ expect(RepoStore.files[0].tempFile).toBeTruthy();
+ expect(RepoStore.files[0].files.length).toBe(1);
+ expect(RepoStore.files[0].files[0].name).toBe('.gitkeep');
+ });
+
+ it('creates multiple trees when entryName has slashes', () => {
+ vm.entryName = 'app/test';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('app');
+ expect(RepoStore.files[0].files[0].name).toBe('test');
+ expect(RepoStore.files[0].files[0].files[0].name).toBe('.gitkeep');
+ });
+
+ it('creates tree in existing tree', () => {
+ RepoStore.files.push(RepoHelper.serializeRepoEntity('tree', {
+ name: 'app',
+ }));
+
+ vm.entryName = 'app/test';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('app');
+ expect(RepoStore.files[0].tempFile).toBeUndefined();
+ expect(RepoStore.files[0].files[0].tempFile).toBeTruthy();
+ expect(RepoStore.files[0].files[0].name).toBe('test');
+ expect(RepoStore.files[0].files[0].files[0].name).toBe('.gitkeep');
+ });
+
+ it('does not create new tree when already exists', () => {
+ RepoStore.files.push(RepoHelper.serializeRepoEntity('tree', {
+ name: 'app',
+ }));
+
+ vm.entryName = 'app';
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(RepoStore.files.length).toBe(1);
+ expect(RepoStore.files[0].name).toBe('app');
+ expect(RepoStore.files[0].tempFile).toBeUndefined();
+ expect(RepoStore.files[0].files.length).toBe(0);
+ });
+ });
+
+ it('focuses field on mount', () => {
+ document.body.innerHTML += '<div class="js-test"></div>';
+
+ vm = createComponent(Component, {
+ type: 'tree',
+ }, '.js-test');
+
+ expect(document.activeElement).toBe(vm.$refs.fieldName);
+
+ vm.$el.remove();
+ });
+});