Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Slaughter <pslaughter@gitlab.com>2018-08-07 18:15:56 +0300
committerPhil Hughes <me@iamphill.com>2018-08-07 18:15:56 +0300
commit0d6e50d54270a973647f828047828b80fdf8d013 (patch)
tree9bf41acf27d039f673f45520187daff9d47cb04f /spec/javascripts
parent0e90f27ff79d1743d8ec5e49e003d4c68a689f78 (diff)
Create Web IDE MR and branch picker
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/helpers/vuex_action_helper.js2
-rw-r--r--spec/javascripts/ide/components/branches/item_spec.js53
-rw-r--r--spec/javascripts/ide/components/branches/search_list_spec.js79
-rw-r--r--spec/javascripts/ide/components/merge_requests/dropdown_spec.js47
-rw-r--r--spec/javascripts/ide/components/merge_requests/item_spec.js15
-rw-r--r--spec/javascripts/ide/components/merge_requests/list_spec.js112
-rw-r--r--spec/javascripts/ide/components/nav_dropdown_button_spec.js63
-rw-r--r--spec/javascripts/ide/components/nav_dropdown_spec.js50
-rw-r--r--spec/javascripts/ide/components/shared/tokened_input_spec.js132
-rw-r--r--spec/javascripts/ide/helpers.js2
-rw-r--r--spec/javascripts/ide/mock_data.js30
-rw-r--r--spec/javascripts/ide/stores/modules/branches/actions_spec.js193
-rw-r--r--spec/javascripts/ide/stores/modules/branches/mutations_spec.js51
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js77
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js19
-rw-r--r--spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js15
16 files changed, 767 insertions, 173 deletions
diff --git a/spec/javascripts/helpers/vuex_action_helper.js b/spec/javascripts/helpers/vuex_action_helper.js
index dd9174194a1..1972408356e 100644
--- a/spec/javascripts/helpers/vuex_action_helper.js
+++ b/spec/javascripts/helpers/vuex_action_helper.js
@@ -84,7 +84,7 @@ export default (
done();
};
- const result = action({ commit, state, dispatch, rootState: state }, payload);
+ const result = action({ commit, state, dispatch, rootState: state, rootGetters: state }, payload);
return new Promise(resolve => {
setImmediate(resolve);
diff --git a/spec/javascripts/ide/components/branches/item_spec.js b/spec/javascripts/ide/components/branches/item_spec.js
new file mode 100644
index 00000000000..8b756c8f168
--- /dev/null
+++ b/spec/javascripts/ide/components/branches/item_spec.js
@@ -0,0 +1,53 @@
+import Vue from 'vue';
+import mountCompontent from 'spec/helpers/vue_mount_component_helper';
+import router from '~/ide/ide_router';
+import Item from '~/ide/components/branches/item.vue';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import { projectData } from '../../mock_data';
+
+const TEST_BRANCH = {
+ name: 'master',
+ committedDate: '2018-01-05T05:50Z',
+};
+const TEST_PROJECT_ID = projectData.name_with_namespace;
+
+describe('IDE branch item', () => {
+ const Component = Vue.extend(Item);
+ let vm;
+
+ beforeEach(() => {
+ vm = mountCompontent(Component, {
+ item: { ...TEST_BRANCH },
+ projectId: TEST_PROJECT_ID,
+ isActive: false,
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders branch name and timeago', () => {
+ const timeText = getTimeago().format(TEST_BRANCH.committedDate);
+ expect(vm.$el).toContainText(TEST_BRANCH.name);
+ expect(vm.$el.querySelector('time')).toHaveText(timeText);
+ expect(vm.$el.querySelector('.ic-mobile-issue-close')).toBe(null);
+ });
+
+ it('renders link to branch', () => {
+ const expectedHref = router.resolve(`/project/${TEST_PROJECT_ID}/edit/${TEST_BRANCH.name}`).href;
+ expect(vm.$el).toMatch('a');
+ expect(vm.$el).toHaveAttr('href', expectedHref);
+ });
+
+ it('renders icon if isActive', done => {
+ vm.isActive = true;
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.ic-mobile-issue-close')).not.toBe(null);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+});
diff --git a/spec/javascripts/ide/components/branches/search_list_spec.js b/spec/javascripts/ide/components/branches/search_list_spec.js
new file mode 100644
index 00000000000..c3f84ba1c24
--- /dev/null
+++ b/spec/javascripts/ide/components/branches/search_list_spec.js
@@ -0,0 +1,79 @@
+import Vue from 'vue';
+import store from '~/ide/stores';
+import * as types from '~/ide/stores/modules/branches/mutation_types';
+import List from '~/ide/components/branches/search_list.vue';
+import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
+import { branches as testBranches } from '../../mock_data';
+import { resetStore } from '../../helpers';
+
+describe('IDE branches search list', () => {
+ const Component = Vue.extend(List);
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponentWithStore(Component, store, {});
+
+ spyOn(vm, 'fetchBranches');
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(store);
+ });
+
+ it('calls fetch on mounted', () => {
+ expect(vm.fetchBranches).toHaveBeenCalledWith({
+ search: '',
+ });
+ });
+
+ it('renders loading icon', done => {
+ vm.$store.state.branches.isLoading = true;
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toContainElement('.loading-container');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders branches not found when search is not empty', done => {
+ vm.search = 'testing';
+
+ vm.$nextTick(() => {
+ expect(vm.$el).toContainText('No branches found');
+
+ done();
+ });
+ });
+
+ describe('with branches', () => {
+ const currentBranch = testBranches[1];
+
+ beforeEach(done => {
+ vm.$store.state.currentBranchId = currentBranch.name;
+ vm.$store.commit(`branches/${types.RECEIVE_BRANCHES_SUCCESS}`, testBranches);
+
+ vm.$nextTick(done);
+ });
+
+ it('renders list', () => {
+ const elementText = Array.from(vm.$el.querySelectorAll('li strong'))
+ .map(x => x.textContent.trim());
+
+ expect(elementText).toEqual(testBranches.map(x => x.name));
+ });
+
+ it('renders check next to active branch', () => {
+ const checkedText = Array.from(vm.$el.querySelectorAll('li'))
+ .filter(x => x.querySelector('.ide-search-list-current-icon svg'))
+ .map(x => x.querySelector('strong').textContent.trim());
+
+ expect(checkedText).toEqual([currentBranch.name]);
+ });
+ });
+});
diff --git a/spec/javascripts/ide/components/merge_requests/dropdown_spec.js b/spec/javascripts/ide/components/merge_requests/dropdown_spec.js
deleted file mode 100644
index 74884c9a362..00000000000
--- a/spec/javascripts/ide/components/merge_requests/dropdown_spec.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import Vue from 'vue';
-import { createStore } from '~/ide/stores';
-import Dropdown from '~/ide/components/merge_requests/dropdown.vue';
-import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
-import { mergeRequests } from '../../mock_data';
-
-describe('IDE merge requests dropdown', () => {
- const Component = Vue.extend(Dropdown);
- let vm;
-
- beforeEach(() => {
- const store = createStore();
-
- vm = createComponentWithStore(Component, store, { show: false }).$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('does not render tabs when show is false', () => {
- expect(vm.$el.querySelector('.nav-links')).toBe(null);
- });
-
- describe('when show is true', () => {
- beforeEach(done => {
- vm.show = true;
- vm.$store.state.mergeRequests.assigned.mergeRequests.push(mergeRequests[0]);
-
- vm.$nextTick(done);
- });
-
- it('renders tabs', () => {
- expect(vm.$el.querySelector('.nav-links')).not.toBe(null);
- });
-
- it('renders count for assigned & created data', () => {
- expect(vm.$el.querySelector('.nav-links a').textContent).toContain('Created by me');
- expect(vm.$el.querySelector('.nav-links a .badge').textContent).toContain('0');
-
- expect(vm.$el.querySelectorAll('.nav-links a')[1].textContent).toContain('Assigned to me');
- expect(
- vm.$el.querySelectorAll('.nav-links a')[1].querySelector('.badge').textContent,
- ).toContain('1');
- });
- });
-});
diff --git a/spec/javascripts/ide/components/merge_requests/item_spec.js b/spec/javascripts/ide/components/merge_requests/item_spec.js
index 51c4cddef2f..750948cae3c 100644
--- a/spec/javascripts/ide/components/merge_requests/item_spec.js
+++ b/spec/javascripts/ide/components/merge_requests/item_spec.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import router from '~/ide/ide_router';
import Item from '~/ide/components/merge_requests/item.vue';
import mountCompontent from '../../../helpers/vue_mount_component_helper';
@@ -27,6 +28,12 @@ describe('IDE merge request item', () => {
expect(vm.$el.textContent).toContain('gitlab-org/gitlab-ce!1');
});
+ it('renders link with href', () => {
+ const expectedHref = router.resolve(`/project/${vm.item.projectPathWithNamespace}/merge_requests/${vm.item.iid}`).href;
+ expect(vm.$el).toMatch('a');
+ expect(vm.$el).toHaveAttr('href', expectedHref);
+ });
+
it('renders icon if ID matches currentId', () => {
expect(vm.$el.querySelector('.ic-mobile-issue-close')).not.toBe(null);
});
@@ -50,12 +57,4 @@ describe('IDE merge request item', () => {
done();
});
});
-
- it('emits click event on click', () => {
- spyOn(vm, '$emit');
-
- vm.$el.click();
-
- expect(vm.$emit).toHaveBeenCalledWith('click', vm.item);
- });
});
diff --git a/spec/javascripts/ide/components/merge_requests/list_spec.js b/spec/javascripts/ide/components/merge_requests/list_spec.js
index f4b393778dc..c761315444c 100644
--- a/spec/javascripts/ide/components/merge_requests/list_spec.js
+++ b/spec/javascripts/ide/components/merge_requests/list_spec.js
@@ -10,10 +10,7 @@ describe('IDE merge requests list', () => {
let vm;
beforeEach(() => {
- vm = createComponentWithStore(Component, store, {
- type: 'created',
- emptyText: 'empty text',
- });
+ vm = createComponentWithStore(Component, store, {});
spyOn(vm, 'fetchMergeRequests');
@@ -28,13 +25,13 @@ describe('IDE merge requests list', () => {
it('calls fetch on mounted', () => {
expect(vm.fetchMergeRequests).toHaveBeenCalledWith({
- type: 'created',
search: '',
+ type: '',
});
});
it('renders loading icon', done => {
- vm.$store.state.mergeRequests.created.isLoading = true;
+ vm.$store.state.mergeRequests.isLoading = true;
vm.$nextTick(() => {
expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
@@ -43,10 +40,6 @@ describe('IDE merge requests list', () => {
});
});
- it('renders empty text when no merge requests exist', () => {
- expect(vm.$el.textContent).toContain('empty text');
- });
-
it('renders no search results text when search is not empty', done => {
vm.search = 'testing';
@@ -57,9 +50,29 @@ describe('IDE merge requests list', () => {
});
});
+ it('clicking on search type, sets currentSearchType and loads merge requests', done => {
+ vm.onSearchFocus();
+
+ vm.$nextTick()
+ .then(() => {
+ vm.$el.querySelector('li button').click();
+
+ return vm.$nextTick();
+ })
+ .then(() => {
+ expect(vm.currentSearchType).toEqual(vm.$options.searchTypes[0]);
+ expect(vm.fetchMergeRequests).toHaveBeenCalledWith({
+ type: vm.currentSearchType.type,
+ search: '',
+ });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
describe('with merge requests', () => {
beforeEach(done => {
- vm.$store.state.mergeRequests.created.mergeRequests.push({
+ vm.$store.state.mergeRequests.mergeRequests.push({
...mergeRequests[0],
projectPathWithNamespace: 'gitlab-org/gitlab-ce',
});
@@ -71,35 +84,6 @@ describe('IDE merge requests list', () => {
expect(vm.$el.querySelectorAll('li').length).toBe(1);
expect(vm.$el.querySelector('li').textContent).toContain(mergeRequests[0].title);
});
-
- it('calls openMergeRequest when clicking merge request', done => {
- spyOn(vm, 'openMergeRequest');
- vm.$el.querySelector('li button').click();
-
- vm.$nextTick(() => {
- expect(vm.openMergeRequest).toHaveBeenCalledWith({
- projectPath: 'gitlab-org/gitlab-ce',
- id: 1,
- });
-
- done();
- });
- });
- });
-
- describe('focusSearch', () => {
- it('focuses search input when loading is false', done => {
- spyOn(vm.$refs.searchInput, 'focus');
-
- vm.$store.state.mergeRequests.created.isLoading = false;
- vm.focusSearch();
-
- vm.$nextTick(() => {
- expect(vm.$refs.searchInput.focus).toHaveBeenCalled();
-
- done();
- });
- });
});
describe('searchMergeRequests', () => {
@@ -123,4 +107,52 @@ describe('IDE merge requests list', () => {
expect(vm.loadMergeRequests).toHaveBeenCalled();
});
});
+
+ describe('onSearchFocus', () => {
+ it('shows search types', done => {
+ vm.$el.querySelector('input').dispatchEvent(new Event('focus'));
+
+ expect(vm.hasSearchFocus).toBe(true);
+ expect(vm.showSearchTypes).toBe(true);
+
+ vm.$nextTick()
+ .then(() => {
+ const expectedSearchTypes = vm.$options.searchTypes.map(x => x.label);
+ const renderedSearchTypes = Array.from(vm.$el.querySelectorAll('li'))
+ .map(x => x.textContent.trim());
+
+ expect(renderedSearchTypes).toEqual(expectedSearchTypes);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does not show search types, if already has search value', () => {
+ vm.search = 'lorem ipsum';
+ vm.$el.querySelector('input').dispatchEvent(new Event('focus'));
+
+ expect(vm.hasSearchFocus).toBe(true);
+ expect(vm.showSearchTypes).toBe(false);
+ });
+
+ it('does not show search types, if already has a search type', () => {
+ vm.currentSearchType = {};
+ vm.$el.querySelector('input').dispatchEvent(new Event('focus'));
+
+ expect(vm.hasSearchFocus).toBe(true);
+ expect(vm.showSearchTypes).toBe(false);
+ });
+
+ it('resets hasSearchFocus when search changes', done => {
+ vm.hasSearchFocus = true;
+ vm.search = 'something else';
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.hasSearchFocus).toBe(false);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
});
diff --git a/spec/javascripts/ide/components/nav_dropdown_button_spec.js b/spec/javascripts/ide/components/nav_dropdown_button_spec.js
new file mode 100644
index 00000000000..0a58e260280
--- /dev/null
+++ b/spec/javascripts/ide/components/nav_dropdown_button_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import NavDropdownButton from '~/ide/components/nav_dropdown_button.vue';
+import store from '~/ide/stores';
+import { trimText } from 'spec/helpers/vue_component_helper';
+import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import { resetStore } from '../helpers';
+
+describe('NavDropdown', () => {
+ const TEST_BRANCH_ID = 'lorem-ipsum-dolar';
+ const TEST_MR_ID = '12345';
+ const Component = Vue.extend(NavDropdownButton);
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, { store });
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(store);
+ });
+
+ it('renders empty placeholders, if state is falsey', () => {
+ expect(trimText(vm.$el.textContent)).toEqual('- -');
+ });
+
+ it('renders branch name, if state has currentBranchId', done => {
+ vm.$store.state.currentBranchId = TEST_BRANCH_ID;
+
+ vm.$nextTick()
+ .then(() => {
+ expect(trimText(vm.$el.textContent)).toEqual(`${TEST_BRANCH_ID} -`);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders mr id, if state has currentMergeRequestId', done => {
+ vm.$store.state.currentMergeRequestId = TEST_MR_ID;
+
+ vm.$nextTick()
+ .then(() => {
+ expect(trimText(vm.$el.textContent)).toEqual(`- !${TEST_MR_ID}`);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders branch and mr, if state has both', done => {
+ vm.$store.state.currentBranchId = TEST_BRANCH_ID;
+ vm.$store.state.currentMergeRequestId = TEST_MR_ID;
+
+ vm.$nextTick()
+ .then(() => {
+ expect(trimText(vm.$el.textContent)).toEqual(`${TEST_BRANCH_ID} !${TEST_MR_ID}`);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+});
diff --git a/spec/javascripts/ide/components/nav_dropdown_spec.js b/spec/javascripts/ide/components/nav_dropdown_spec.js
new file mode 100644
index 00000000000..af6665bcd62
--- /dev/null
+++ b/spec/javascripts/ide/components/nav_dropdown_spec.js
@@ -0,0 +1,50 @@
+import $ from 'jquery';
+import Vue from 'vue';
+import store from '~/ide/stores';
+import NavDropdown from '~/ide/components/nav_dropdown.vue';
+import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+
+describe('IDE NavDropdown', () => {
+ const Component = Vue.extend(NavDropdown);
+ let vm;
+ let $dropdown;
+
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, { store });
+ $dropdown = $(vm.$el);
+
+ // block dispatch from doing anything
+ spyOn(vm.$store, 'dispatch');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders nothing initially', () => {
+ expect(vm.$el).not.toContainElement('.ide-nav-form');
+ });
+
+ it('renders nav form when show.bs.dropdown', done => {
+ $dropdown.trigger('show.bs.dropdown');
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).toContainElement('.ide-nav-form');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('destroys nav form when closed', done => {
+ $dropdown.trigger('show.bs.dropdown');
+ $dropdown.trigger('hide.bs.dropdown');
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el).not.toContainElement('.ide-nav-form');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+});
diff --git a/spec/javascripts/ide/components/shared/tokened_input_spec.js b/spec/javascripts/ide/components/shared/tokened_input_spec.js
new file mode 100644
index 00000000000..09940fe8c6a
--- /dev/null
+++ b/spec/javascripts/ide/components/shared/tokened_input_spec.js
@@ -0,0 +1,132 @@
+import Vue from 'vue';
+import TokenedInput from '~/ide/components/shared/tokened_input.vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+
+const TEST_PLACEHOLDER = 'Searching in test';
+const TEST_TOKENS = [
+ { label: 'lorem', id: 1 },
+ { label: 'ipsum', id: 2 },
+ { label: 'dolar', id: 3 },
+];
+const TEST_VALUE = 'lorem';
+
+function getTokenElements(vm) {
+ return Array.from(vm.$el.querySelectorAll('.filtered-search-token button'));
+}
+
+function createBackspaceEvent() {
+ const e = new Event('keyup');
+ e.keyCode = 8;
+ e.which = e.keyCode;
+ e.altKey = false;
+ e.ctrlKey = true;
+ e.shiftKey = false;
+ e.metaKey = false;
+ return e;
+}
+
+describe('IDE shared/TokenedInput', () => {
+ const Component = Vue.extend(TokenedInput);
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ tokens: TEST_TOKENS,
+ placeholder: TEST_PLACEHOLDER,
+ value: TEST_VALUE,
+ });
+
+ spyOn(vm, '$emit');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders tokens', () => {
+ const renderedTokens = getTokenElements(vm)
+ .map(x => x.textContent.trim());
+
+ expect(renderedTokens).toEqual(TEST_TOKENS.map(x => x.label));
+ });
+
+ it('renders input', () => {
+ expect(vm.$refs.input).toBeTruthy();
+ expect(vm.$refs.input).toHaveValue(TEST_VALUE);
+ });
+
+ it('renders placeholder, when tokens are empty', done => {
+ vm.tokens = [];
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$refs.input).toHaveAttr('placeholder', TEST_PLACEHOLDER);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('triggers "removeToken" on token click', () => {
+ getTokenElements(vm)[0].click();
+
+ expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[0]);
+ });
+
+ it('when input triggers backspace event, it calls "onBackspace"', () => {
+ spyOn(vm, 'onBackspace');
+
+ vm.$refs.input.dispatchEvent(createBackspaceEvent());
+ vm.$refs.input.dispatchEvent(createBackspaceEvent());
+
+ expect(vm.onBackspace).toHaveBeenCalledTimes(2);
+ });
+
+ it('triggers "removeToken" on backspaces when value is empty', () => {
+ vm.value = '';
+
+ vm.onBackspace();
+ expect(vm.$emit).not.toHaveBeenCalled();
+ expect(vm.backspaceCount).toEqual(1);
+
+ vm.onBackspace();
+ expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[TEST_TOKENS.length - 1]);
+ expect(vm.backspaceCount).toEqual(0);
+ });
+
+ it('does not trigger "removeToken" on backspaces when value is not empty', () => {
+ vm.onBackspace();
+ vm.onBackspace();
+
+ expect(vm.backspaceCount).toEqual(0);
+ expect(vm.$emit).not.toHaveBeenCalled();
+ });
+
+ it('does not trigger "removeToken" on backspaces when tokens are empty', () => {
+ vm.tokens = [];
+
+ vm.onBackspace();
+ vm.onBackspace();
+
+ expect(vm.backspaceCount).toEqual(0);
+ expect(vm.$emit).not.toHaveBeenCalled();
+ });
+
+ it('triggers "focus" on input focus', () => {
+ vm.$refs.input.dispatchEvent(new Event('focus'));
+
+ expect(vm.$emit).toHaveBeenCalledWith('focus');
+ });
+
+ it('triggers "blur" on input blur', () => {
+ vm.$refs.input.dispatchEvent(new Event('blur'));
+
+ expect(vm.$emit).toHaveBeenCalledWith('blur');
+ });
+
+ it('triggers "input" with value on input change', () => {
+ vm.$refs.input.value = 'something-else';
+ vm.$refs.input.dispatchEvent(new Event('input'));
+
+ expect(vm.$emit).toHaveBeenCalledWith('input', 'something-else');
+ });
+});
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
index 569fa5c7aae..c11c482fef8 100644
--- a/spec/javascripts/ide/helpers.js
+++ b/spec/javascripts/ide/helpers.js
@@ -4,6 +4,7 @@ import state from '~/ide/stores/state';
import commitState from '~/ide/stores/modules/commit/state';
import mergeRequestsState from '~/ide/stores/modules/merge_requests/state';
import pipelinesState from '~/ide/stores/modules/pipelines/state';
+import branchesState from '~/ide/stores/modules/branches/state';
export const resetStore = store => {
const newState = {
@@ -11,6 +12,7 @@ export const resetStore = store => {
commit: commitState(),
mergeRequests: mergeRequestsState(),
pipelines: pipelinesState(),
+ branches: branchesState(),
};
store.replaceState(newState);
};
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index 7be450a0df7..4fe826943b2 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -165,3 +165,33 @@ export const mergeRequests = [
web_url: `${gl.TEST_HOST}/namespace/project-path/merge_requests/1`,
},
];
+
+export const branches = [
+ {
+ id: 1,
+ name: 'master',
+ commit: {
+ message: 'Update master branch',
+ committed_date: '2018-08-01T00:20:05Z',
+ },
+ can_push: true,
+ },
+ {
+ id: 2,
+ name: 'feature/lorem-ipsum',
+ commit: {
+ message: 'Update some stuff',
+ committed_date: '2018-08-02T00:00:05Z',
+ },
+ can_push: true,
+ },
+ {
+ id: 3,
+ name: 'feature/dolar-amit',
+ commit: {
+ message: 'Update some more stuff',
+ committed_date: '2018-06-30T00:20:05Z',
+ },
+ can_push: true,
+ },
+];
diff --git a/spec/javascripts/ide/stores/modules/branches/actions_spec.js b/spec/javascripts/ide/stores/modules/branches/actions_spec.js
new file mode 100644
index 00000000000..a0fce578958
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/branches/actions_spec.js
@@ -0,0 +1,193 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import state from '~/ide/stores/modules/branches/state';
+import * as types from '~/ide/stores/modules/branches/mutation_types';
+import testAction from 'spec/helpers/vuex_action_helper';
+import {
+ requestBranches,
+ receiveBranchesError,
+ receiveBranchesSuccess,
+ fetchBranches,
+ resetBranches,
+ openBranch,
+} from '~/ide/stores/modules/branches/actions';
+import { branches, projectData } from '../../../mock_data';
+
+describe('IDE branches actions', () => {
+ const TEST_SEARCH = 'foosearch';
+ let mockedContext;
+ let mockedState;
+ let mock;
+
+ beforeEach(() => {
+ mockedContext = {
+ dispatch() {},
+ rootState: {
+ currentProjectId: projectData.name_with_namespace,
+ },
+ rootGetters: {
+ currentProject: projectData,
+ },
+ state: state(),
+ };
+
+ // testAction looks for rootGetters in state,
+ // so they need to be concatenated here.
+ mockedState = {
+ ...mockedContext.state,
+ ...mockedContext.rootGetters,
+ ...mockedContext.rootState,
+ };
+
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('requestBranches', () => {
+ it('should commit request', done => {
+ testAction(
+ requestBranches,
+ null,
+ mockedContext.state,
+ [{ type: types.REQUEST_BRANCHES }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveBranchesError', () => {
+ it('should should commit error', done => {
+
+ testAction(
+ receiveBranchesError,
+ { search: TEST_SEARCH },
+ mockedContext.state,
+ [{ type: types.RECEIVE_BRANCHES_ERROR }],
+ [
+ {
+ type: 'setErrorMessage',
+ payload: {
+ text: 'Error loading branches.',
+ action: jasmine.any(Function),
+ actionText: 'Please try again',
+ actionPayload: { search: TEST_SEARCH },
+ },
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('receiveBranchesSuccess', () => {
+ it('should commit received data', done => {
+ testAction(
+ receiveBranchesSuccess,
+ branches,
+ mockedContext.state,
+ [{ type: types.RECEIVE_BRANCHES_SUCCESS, payload: branches }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('fetchBranches', () => {
+ beforeEach(() => {
+ gon.api_version = 'v4';
+ });
+
+ describe('success', () => {
+ beforeEach(() => {
+ mock.onGet(/\/api\/v4\/projects\/\d+\/repository\/branches(.*)$/).replyOnce(200, branches);
+ });
+
+ it('calls API with params', () => {
+ const apiSpy = spyOn(axios, 'get').and.callThrough();
+
+ fetchBranches(mockedContext, { search: TEST_SEARCH });
+
+ expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), {
+ params: jasmine.objectContaining({
+ search: TEST_SEARCH,
+ sort: 'updated_desc',
+ }),
+ });
+ });
+
+ it('dispatches success with received data', done => {
+ testAction(
+ fetchBranches,
+ { search: TEST_SEARCH },
+ mockedState,
+ [],
+ [
+ { type: 'requestBranches' },
+ { type: 'resetBranches' },
+ {
+ type: 'receiveBranchesSuccess',
+ payload: branches,
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(/\/api\/v4\/projects\/\d+\/repository\/branches(.*)$/).replyOnce(500);
+ });
+
+ it('dispatches error', done => {
+ testAction(
+ fetchBranches,
+ { search: TEST_SEARCH },
+ mockedState,
+ [],
+ [
+ { type: 'requestBranches' },
+ { type: 'resetBranches' },
+ {
+ type: 'receiveBranchesError',
+ payload: { search: TEST_SEARCH },
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('resetBranches', () => {
+ it('commits reset', done => {
+ testAction(
+ resetBranches,
+ null,
+ mockedContext.state,
+ [{ type: types.RESET_BRANCHES }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('openBranch', () => {
+ it('dispatches goToRoute action with path', done => {
+ const branchId = branches[0].name;
+ const expectedPath = `/project/${projectData.name_with_namespace}/edit/${branchId}`;
+ testAction(
+ openBranch,
+ branchId,
+ mockedState,
+ [],
+ [{ type: 'goToRoute', payload: expectedPath }],
+ done,
+ );
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/branches/mutations_spec.js b/spec/javascripts/ide/stores/modules/branches/mutations_spec.js
new file mode 100644
index 00000000000..be91440f119
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/branches/mutations_spec.js
@@ -0,0 +1,51 @@
+import state from '~/ide/stores/modules/branches/state';
+import mutations from '~/ide/stores/modules/branches/mutations';
+import * as types from '~/ide/stores/modules/branches/mutation_types';
+import { branches } from '../../../mock_data';
+
+describe('IDE branches mutations', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state();
+ });
+
+ describe(types.REQUEST_BRANCHES, () => {
+ it('sets loading to true', () => {
+ mutations[types.REQUEST_BRANCHES](mockedState);
+
+ expect(mockedState.isLoading).toBe(true);
+ });
+ });
+
+ describe(types.RECEIVE_BRANCHES_ERROR, () => {
+ it('sets loading to false', () => {
+ mutations[types.RECEIVE_BRANCHES_ERROR](mockedState);
+
+ expect(mockedState.isLoading).toBe(false);
+ });
+ });
+
+ describe(types.RECEIVE_BRANCHES_SUCCESS, () => {
+ it('sets branches', () => {
+ const expectedBranches = branches.map(branch => ({
+ name: branch.name,
+ committedDate: branch.commit.committed_date,
+ }));
+
+ mutations[types.RECEIVE_BRANCHES_SUCCESS](mockedState, branches);
+
+ expect(mockedState.branches).toEqual(expectedBranches);
+ });
+ });
+
+ describe(types.RESET_BRANCHES, () => {
+ it('clears branches array', () => {
+ mockedState.branches = ['test'];
+
+ mutations[types.RESET_BRANCHES](mockedState);
+
+ expect(mockedState.branches).toEqual([]);
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js
index d063f1ea860..62699143a91 100644
--- a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js
@@ -8,9 +8,7 @@ import {
receiveMergeRequestsSuccess,
fetchMergeRequests,
resetMergeRequests,
- openMergeRequest,
} from '~/ide/stores/modules/merge_requests/actions';
-import router from '~/ide/ide_router';
import { mergeRequests } from '../../../mock_data';
import testAction from '../../../../helpers/vuex_action_helper';
@@ -28,12 +26,12 @@ describe('IDE merge requests actions', () => {
});
describe('requestMergeRequests', () => {
- it('should should commit request', done => {
+ it('should commit request', done => {
testAction(
requestMergeRequests,
- 'created',
+ null,
mockedState,
- [{ type: types.REQUEST_MERGE_REQUESTS, payload: 'created' }],
+ [{ type: types.REQUEST_MERGE_REQUESTS }],
[],
done,
);
@@ -46,7 +44,7 @@ describe('IDE merge requests actions', () => {
receiveMergeRequestsError,
{ type: 'created', search: '' },
mockedState,
- [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR, payload: 'created' }],
+ [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR }],
[
{
type: 'setErrorMessage',
@@ -67,12 +65,12 @@ describe('IDE merge requests actions', () => {
it('should commit received data', done => {
testAction(
receiveMergeRequestsSuccess,
- { type: 'created', data: 'data' },
+ mergeRequests,
mockedState,
[
{
type: types.RECEIVE_MERGE_REQUESTS_SUCCESS,
- payload: { type: 'created', data: 'data' },
+ payload: mergeRequests,
},
],
[],
@@ -129,11 +127,11 @@ describe('IDE merge requests actions', () => {
mockedState,
[],
[
- { type: 'requestMergeRequests', payload: 'created' },
- { type: 'resetMergeRequests', payload: 'created' },
+ { type: 'requestMergeRequests' },
+ { type: 'resetMergeRequests' },
{
type: 'receiveMergeRequestsSuccess',
- payload: { type: 'created', data: mergeRequests },
+ payload: mergeRequests,
},
],
done,
@@ -149,12 +147,12 @@ describe('IDE merge requests actions', () => {
it('dispatches error', done => {
testAction(
fetchMergeRequests,
- { type: 'created' },
+ { type: 'created', search: '' },
mockedState,
[],
[
- { type: 'requestMergeRequests', payload: 'created' },
- { type: 'resetMergeRequests', payload: 'created' },
+ { type: 'requestMergeRequests' },
+ { type: 'resetMergeRequests' },
{ type: 'receiveMergeRequestsError', payload: { type: 'created', search: '' } },
],
done,
@@ -167,59 +165,12 @@ describe('IDE merge requests actions', () => {
it('commits reset', done => {
testAction(
resetMergeRequests,
- 'created',
+ null,
mockedState,
- [{ type: types.RESET_MERGE_REQUESTS, payload: 'created' }],
+ [{ type: types.RESET_MERGE_REQUESTS }],
[],
done,
);
});
});
-
- describe('openMergeRequest', () => {
- beforeEach(() => {
- spyOn(router, 'push');
- });
-
- it('commits reset mutations and actions', done => {
- const commit = jasmine.createSpy();
- const dispatch = jasmine.createSpy().and.returnValue(Promise.resolve());
- openMergeRequest({ commit, dispatch }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' });
-
- setTimeout(() => {
- expect(commit.calls.argsFor(0)).toEqual(['CLEAR_PROJECTS', null, { root: true }]);
- expect(commit.calls.argsFor(1)).toEqual(['SET_CURRENT_MERGE_REQUEST', '1', { root: true }]);
- expect(commit.calls.argsFor(2)).toEqual(['RESET_OPEN_FILES', null, { root: true }]);
-
- expect(dispatch.calls.argsFor(0)).toEqual(['setCurrentBranchId', '', { root: true }]);
- expect(dispatch.calls.argsFor(1)).toEqual([
- 'pipelines/stopPipelinePolling',
- null,
- { root: true },
- ]);
- expect(dispatch.calls.argsFor(2)).toEqual(['setRightPane', null, { root: true }]);
- expect(dispatch.calls.argsFor(3)).toEqual([
- 'pipelines/resetLatestPipeline',
- null,
- { root: true },
- ]);
- expect(dispatch.calls.argsFor(4)).toEqual([
- 'pipelines/clearEtagPoll',
- null,
- { root: true },
- ]);
-
- done();
- });
- });
-
- it('pushes new route', () => {
- openMergeRequest(
- { commit() {}, dispatch: () => Promise.resolve() },
- { projectPath: 'gitlab-org/gitlab-ce', id: '1' },
- );
-
- expect(router.push).toHaveBeenCalledWith('/project/gitlab-org/gitlab-ce/merge_requests/1');
- });
- });
});
diff --git a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js
index ea03131d90d..664d3914564 100644
--- a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js
+++ b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js
@@ -12,29 +12,26 @@ describe('IDE merge requests mutations', () => {
describe(types.REQUEST_MERGE_REQUESTS, () => {
it('sets loading to true', () => {
- mutations[types.REQUEST_MERGE_REQUESTS](mockedState, 'created');
+ mutations[types.REQUEST_MERGE_REQUESTS](mockedState);
- expect(mockedState.created.isLoading).toBe(true);
+ expect(mockedState.isLoading).toBe(true);
});
});
describe(types.RECEIVE_MERGE_REQUESTS_ERROR, () => {
it('sets loading to false', () => {
- mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState, 'created');
+ mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState);
- expect(mockedState.created.isLoading).toBe(false);
+ expect(mockedState.isLoading).toBe(false);
});
});
describe(types.RECEIVE_MERGE_REQUESTS_SUCCESS, () => {
it('sets merge requests', () => {
gon.gitlab_url = gl.TEST_HOST;
- mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, {
- type: 'created',
- data: mergeRequests,
- });
+ mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, mergeRequests);
- expect(mockedState.created.mergeRequests).toEqual([
+ expect(mockedState.mergeRequests).toEqual([
{
id: 1,
iid: 1,
@@ -50,9 +47,9 @@ describe('IDE merge requests mutations', () => {
it('clears merge request array', () => {
mockedState.mergeRequests = ['test'];
- mutations[types.RESET_MERGE_REQUESTS](mockedState, 'created');
+ mutations[types.RESET_MERGE_REQUESTS](mockedState);
- expect(mockedState.created.mergeRequests).toEqual([]);
+ expect(mockedState.mergeRequests).toEqual([]);
});
});
});
diff --git a/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js b/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js
index ba897f4660d..2796cd088c6 100644
--- a/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js
+++ b/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js
@@ -2,15 +2,15 @@ import Vue from 'vue';
import dropdownButtonComponent from '~/vue_shared/components/dropdown/dropdown_button.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
+import { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper';
const defaultLabel = 'Select';
const customLabel = 'Select project';
-const createComponent = config => {
+const createComponent = (props, slots = {}) => {
const Component = Vue.extend(dropdownButtonComponent);
- return mountComponent(Component, config);
+ return mountComponentWithSlots(Component, { props, slots });
};
describe('DropdownButtonComponent', () => {
@@ -65,5 +65,14 @@ describe('DropdownButtonComponent', () => {
expect(dropdownIconEl).not.toBeNull();
expect(dropdownIconEl.classList.contains('fa-chevron-down')).toBe(true);
});
+
+ it('renders slot, if default slot exists', () => {
+ vm = createComponent({}, {
+ default: ['Lorem Ipsum Dolar'],
+ });
+
+ expect(vm.$el).not.toContainElement('.dropdown-toggle-text');
+ expect(vm.$el).toHaveText('Lorem Ipsum Dolar');
+ });
});
});