summaryrefslogtreecommitdiff
path: root/spec/javascripts
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2017-08-03 13:13:06 +0200
committerDouwe Maan <douwe@selenight.nl>2017-08-03 13:13:06 +0200
commit2197ee02e95ade455785cc1769bf3a40a082a799 (patch)
tree387a303a1bce6e5002c78a6d41c904ceffe2b357 /spec/javascripts
parentd0ffbd18fa5be4e90d150bc617d0cc7eb3c8720b (diff)
parent1018ab0516fd94d1ffbc05a0ad8499947dd9630d (diff)
downloadgitlab-ce-2197ee02e95ade455785cc1769bf3a40a082a799.tar.gz
Merge branch 'master' into ide
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/droplab/plugins/ajax_spec.js36
-rw-r--r--spec/javascripts/filtered_search/dropdown_utils_spec.js96
-rw-r--r--spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js63
-rw-r--r--spec/javascripts/fixtures/balsamiq.rb2
-rw-r--r--spec/javascripts/fixtures/deploy_keys.rb2
-rw-r--r--spec/javascripts/fixtures/merge_requests.rb2
-rw-r--r--spec/javascripts/fixtures/merge_requests_diffs.rb2
-rw-r--r--spec/javascripts/fixtures/pdf.rb2
-rw-r--r--spec/javascripts/fixtures/raw.rb2
-rw-r--r--spec/javascripts/fly_out_nav_spec.js180
-rw-r--r--spec/javascripts/groups/group_identicon_spec.js60
-rw-r--r--spec/javascripts/groups/groups_spec.js13
-rw-r--r--spec/javascripts/groups/mock_data.js4
-rw-r--r--spec/javascripts/lib/utils/ajax_cache_spec.js9
-rw-r--r--spec/javascripts/projects/project_new_spec.js127
15 files changed, 592 insertions, 8 deletions
diff --git a/spec/javascripts/droplab/plugins/ajax_spec.js b/spec/javascripts/droplab/plugins/ajax_spec.js
new file mode 100644
index 00000000000..085f25764fe
--- /dev/null
+++ b/spec/javascripts/droplab/plugins/ajax_spec.js
@@ -0,0 +1,36 @@
+import AjaxCache from '~/lib/utils/ajax_cache';
+import Ajax from '~/droplab/plugins/ajax';
+
+describe('Ajax', () => {
+ describe('preprocessing', () => {
+ const config = {};
+
+ describe('is not configured', () => {
+ it('passes the data through', () => {
+ const data = ['data'];
+ expect(Ajax.preprocessing(config, data)).toEqual(data);
+ });
+ });
+
+ describe('is configured', () => {
+ const processedArray = ['processed'];
+
+ beforeEach(() => {
+ config.preprocessing = () => processedArray;
+ spyOn(config, 'preprocessing').and.callFake(() => processedArray);
+ });
+
+ it('calls preprocessing', () => {
+ Ajax.preprocessing(config, []);
+ expect(config.preprocessing.calls.count()).toBe(1);
+ });
+
+ it('overrides AjaxCache', () => {
+ spyOn(AjaxCache, 'override').and.callFake((endpoint, results) => expect(results).toEqual(processedArray));
+
+ Ajax.preprocessing(config, []);
+ expect(AjaxCache.override.calls.count()).toBe(1);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js
index f55726379f3..244f170ab7a 100644
--- a/spec/javascripts/filtered_search/dropdown_utils_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js
@@ -191,6 +191,102 @@ describe('Dropdown Utils', () => {
});
});
+ describe('mergeDuplicateLabels', () => {
+ const dataMap = {
+ label: {
+ title: 'label',
+ color: '#FFFFFF',
+ },
+ };
+
+ it('should add label to dataMap if it is not a duplicate', () => {
+ const newLabel = {
+ title: 'new-label',
+ color: '#000000',
+ };
+
+ const updated = gl.DropdownUtils.mergeDuplicateLabels(dataMap, newLabel);
+ expect(updated[newLabel.title]).toEqual(newLabel);
+ });
+
+ it('should merge colors if label is a duplicate', () => {
+ const duplicate = {
+ title: 'label',
+ color: '#000000',
+ };
+
+ const updated = gl.DropdownUtils.mergeDuplicateLabels(dataMap, duplicate);
+ expect(updated.label.multipleColors).toEqual([dataMap.label.color, duplicate.color]);
+ });
+ });
+
+ describe('duplicateLabelColor', () => {
+ it('should linear-gradient 2 colors', () => {
+ const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000']);
+ expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 50%, #000000 50%, #000000 100%)');
+ });
+
+ it('should linear-gradient 3 colors', () => {
+ const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333']);
+ expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 33%, #000000 33%, #000000 66%, #333333 66%, #333333 100%)');
+ });
+
+ it('should linear-gradient 4 colors', () => {
+ const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333', '#DDDDDD']);
+ expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 25%, #000000 25%, #000000 50%, #333333 50%, #333333 75%, #DDDDDD 75%, #DDDDDD 100%)');
+ });
+
+ it('should not linear-gradient more than 4 colors', () => {
+ const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333', '#DDDDDD', '#EEEEEE']);
+ expect(gradient.indexOf('#EEEEEE') === -1).toEqual(true);
+ });
+ });
+
+ describe('duplicateLabelPreprocessing', () => {
+ it('should set preprocessed to true', () => {
+ const results = gl.DropdownUtils.duplicateLabelPreprocessing([]);
+ expect(results.preprocessed).toEqual(true);
+ });
+
+ it('should not mutate existing data if there are no duplicates', () => {
+ const data = [{
+ title: 'label1',
+ color: '#FFFFFF',
+ }, {
+ title: 'label2',
+ color: '#000000',
+ }];
+ const results = gl.DropdownUtils.duplicateLabelPreprocessing(data);
+
+ expect(results.length).toEqual(2);
+ expect(results[0]).toEqual(data[0]);
+ expect(results[1]).toEqual(data[1]);
+ });
+
+ describe('duplicate labels', () => {
+ const data = [{
+ title: 'label',
+ color: '#FFFFFF',
+ }, {
+ title: 'label',
+ color: '#000000',
+ }];
+ const results = gl.DropdownUtils.duplicateLabelPreprocessing(data);
+
+ it('should merge duplicate labels', () => {
+ expect(results.length).toEqual(1);
+ });
+
+ it('should convert multiple colored labels into linear-gradient', () => {
+ expect(results[0].color).toEqual(gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000']));
+ });
+
+ it('should set multiple colored label text color to black', () => {
+ expect(results[0].text_color).toEqual('#000000');
+ });
+ });
+ });
+
describe('setDataValueIfSelected', () => {
beforeEach(() => {
spyOn(gl.FilteredSearchDropdownManager, 'addWordToInput')
diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
index fa4343ffbc8..67166802c70 100644
--- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
@@ -797,6 +797,69 @@ describe('Filtered Search Visual Tokens', () => {
});
});
+ describe('setTokenStyle', () => {
+ let originalTextColor;
+
+ beforeEach(() => {
+ originalTextColor = bugLabelToken.style.color;
+ });
+
+ it('should set backgroundColor', () => {
+ const originalBackgroundColor = bugLabelToken.style.backgroundColor;
+ const token = subject.setTokenStyle(bugLabelToken, 'blue', 'white');
+ expect(token.style.backgroundColor).toEqual('blue');
+ expect(token.style.backgroundColor).not.toEqual(originalBackgroundColor);
+ });
+
+ it('should not set backgroundColor when it is a linear-gradient', () => {
+ const token = subject.setTokenStyle(bugLabelToken, 'linear-gradient(135deg, red, blue)', 'white');
+ expect(token.style.backgroundColor).toEqual(bugLabelToken.style.backgroundColor);
+ });
+
+ it('should set textColor', () => {
+ const token = subject.setTokenStyle(bugLabelToken, 'white', 'black');
+ expect(token.style.color).toEqual('black');
+ expect(token.style.color).not.toEqual(originalTextColor);
+ });
+
+ it('should add inverted class when textColor is #FFFFFF', () => {
+ const token = subject.setTokenStyle(bugLabelToken, 'black', '#FFFFFF');
+ expect(token.style.color).toEqual('rgb(255, 255, 255)');
+ expect(token.style.color).not.toEqual(originalTextColor);
+ expect(token.querySelector('.remove-token').classList.contains('inverted')).toEqual(true);
+ });
+ });
+
+ describe('preprocessLabel', () => {
+ const endpoint = 'endpoint';
+
+ it('does not preprocess more than once', () => {
+ let labels = [];
+
+ spyOn(gl.DropdownUtils, 'duplicateLabelPreprocessing').and.callFake(() => []);
+
+ labels = gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels);
+ gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels);
+
+ expect(gl.DropdownUtils.duplicateLabelPreprocessing.calls.count()).toEqual(1);
+ });
+
+ describe('not preprocessed before', () => {
+ it('returns preprocessed labels', () => {
+ let labels = [];
+ expect(labels.preprocessed).not.toEqual(true);
+ labels = gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels);
+ expect(labels.preprocessed).toEqual(true);
+ });
+
+ it('overrides AjaxCache with preprocessed results', () => {
+ spyOn(AjaxCache, 'override').and.callFake(() => {});
+ gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, []);
+ expect(AjaxCache.override.calls.count()).toEqual(1);
+ });
+ });
+ });
+
describe('updateLabelTokenColor', () => {
const jsonFixtureName = 'labels/project_labels.json';
const dummyEndpoint = '/dummy/endpoint';
diff --git a/spec/javascripts/fixtures/balsamiq.rb b/spec/javascripts/fixtures/balsamiq.rb
index b5372821bf5..234e246119a 100644
--- a/spec/javascripts/fixtures/balsamiq.rb
+++ b/spec/javascripts/fixtures/balsamiq.rb
@@ -4,7 +4,7 @@ describe 'Balsamiq file', '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project, namespace: namespace, path: 'balsamiq-project') }
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'balsamiq-project') }
before(:all) do
clean_frontend_fixtures('blob/balsamiq/')
diff --git a/spec/javascripts/fixtures/deploy_keys.rb b/spec/javascripts/fixtures/deploy_keys.rb
index 16e598a4b29..fca3f5b1bfe 100644
--- a/spec/javascripts/fixtures/deploy_keys.rb
+++ b/spec/javascripts/fixtures/deploy_keys.rb
@@ -6,7 +6,7 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') }
- let(:project2) { create(:empty_project, :internal)}
+ let(:project2) { create(:project, :internal)}
before(:all) do
clean_frontend_fixtures('deploy_keys/')
diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb
index 7e2f364ffa4..f9d8b5c569c 100644
--- a/spec/javascripts/fixtures/merge_requests.rb
+++ b/spec/javascripts/fixtures/merge_requests.rb
@@ -5,7 +5,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') }
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
let(:merged_merge_request) { create(:merge_request, :merged, source_project: project, target_project: project) }
let(:pipeline) do
diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb
index ac5b06ace6d..4481a187f63 100644
--- a/spec/javascripts/fixtures/merge_requests_diffs.rb
+++ b/spec/javascripts/fixtures/merge_requests_diffs.rb
@@ -6,7 +6,7 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') }
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
diff --git a/spec/javascripts/fixtures/pdf.rb b/spec/javascripts/fixtures/pdf.rb
index 6b2422a7986..ef9976b9fd3 100644
--- a/spec/javascripts/fixtures/pdf.rb
+++ b/spec/javascripts/fixtures/pdf.rb
@@ -4,7 +4,7 @@ describe 'PDF file', '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project, namespace: namespace, path: 'pdf-project') }
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'pdf-project') }
before(:all) do
clean_frontend_fixtures('blob/pdf/')
diff --git a/spec/javascripts/fixtures/raw.rb b/spec/javascripts/fixtures/raw.rb
index 17533443d76..25f5a3b0bb3 100644
--- a/spec/javascripts/fixtures/raw.rb
+++ b/spec/javascripts/fixtures/raw.rb
@@ -4,7 +4,7 @@ describe 'Raw files', '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project, namespace: namespace, path: 'raw-project') }
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'raw-project') }
before(:all) do
clean_frontend_fixtures('blob/notebook/')
diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js
new file mode 100644
index 00000000000..ab74f3e00ec
--- /dev/null
+++ b/spec/javascripts/fly_out_nav_spec.js
@@ -0,0 +1,180 @@
+/* global bp */
+import {
+ calculateTop,
+ hideSubLevelItems,
+ showSubLevelItems,
+ canShowSubItems,
+} from '~/fly_out_nav';
+
+describe('Fly out sidebar navigation', () => {
+ let el;
+ let breakpointSize = 'lg';
+
+ beforeEach(() => {
+ el = document.createElement('div');
+ el.style.position = 'relative';
+ document.body.appendChild(el);
+
+ spyOn(bp, 'getBreakpointSize').and.callFake(() => breakpointSize);
+ });
+
+ afterEach(() => {
+ el.remove();
+ breakpointSize = 'lg';
+ });
+
+ describe('calculateTop', () => {
+ it('returns boundingRect top', () => {
+ const boundingRect = {
+ top: 100,
+ height: 100,
+ };
+
+ expect(
+ calculateTop(boundingRect, 100),
+ ).toBe(100);
+ });
+
+ it('returns boundingRect - bottomOverflow', () => {
+ const boundingRect = {
+ top: window.innerHeight - 50,
+ height: 100,
+ };
+
+ expect(
+ calculateTop(boundingRect, 100),
+ ).toBe(window.innerHeight - 50);
+ });
+ });
+
+ describe('hideSubLevelItems', () => {
+ beforeEach(() => {
+ el.innerHTML = '<div class="sidebar-sub-level-items"></div>';
+ });
+
+ it('hides subitems', () => {
+ hideSubLevelItems(el);
+
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).toBe('none');
+ });
+
+ it('does not hude subitems on mobile', () => {
+ breakpointSize = 'sm';
+
+ hideSubLevelItems(el);
+
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).not.toBe('none');
+ });
+
+ it('removes is-over class', () => {
+ spyOn(el.classList, 'remove');
+
+ hideSubLevelItems(el);
+
+ expect(
+ el.classList.remove,
+ ).toHaveBeenCalledWith('is-over');
+ });
+
+ it('removes is-above class from sub-items', () => {
+ const subItems = el.querySelector('.sidebar-sub-level-items');
+
+ spyOn(subItems.classList, 'remove');
+
+ hideSubLevelItems(el);
+
+ expect(
+ subItems.classList.remove,
+ ).toHaveBeenCalledWith('is-above');
+ });
+
+ it('does nothing if el has no sub-items', () => {
+ el.innerHTML = '';
+
+ spyOn(el.classList, 'remove');
+
+ hideSubLevelItems(el);
+
+ expect(
+ el.classList.remove,
+ ).not.toHaveBeenCalledWith();
+ });
+ });
+
+ describe('showSubLevelItems', () => {
+ beforeEach(() => {
+ el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute;"></div>';
+ });
+
+ it('adds is-over class to el', () => {
+ spyOn(el.classList, 'add');
+
+ showSubLevelItems(el);
+
+ expect(
+ el.classList.add,
+ ).toHaveBeenCalledWith('is-over');
+ });
+
+ it('does not show sub-items on mobile', () => {
+ breakpointSize = 'sm';
+
+ showSubLevelItems(el);
+
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).not.toBe('block');
+ });
+
+ it('does not shows sub-items', () => {
+ showSubLevelItems(el);
+
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).toBe('block');
+ });
+
+ it('sets transform of sub-items', () => {
+ const subItems = el.querySelector('.sidebar-sub-level-items');
+ showSubLevelItems(el);
+
+ expect(
+ subItems.style.transform,
+ ).toBe(`translate3d(0px, ${Math.floor(el.getBoundingClientRect().top)}px, 0px)`);
+ });
+
+ it('sets is-above when element is above', () => {
+ const subItems = el.querySelector('.sidebar-sub-level-items');
+ subItems.style.height = `${window.innerHeight + el.offsetHeight}px`;
+ el.style.top = `${window.innerHeight - el.offsetHeight}px`;
+
+ spyOn(subItems.classList, 'add');
+
+ showSubLevelItems(el);
+
+ expect(
+ subItems.classList.add,
+ ).toHaveBeenCalledWith('is-above');
+ });
+ });
+
+ describe('canShowSubItems', () => {
+ it('returns true if on desktop size', () => {
+ expect(
+ canShowSubItems(),
+ ).toBeTruthy();
+ });
+
+ it('returns false if on mobile size', () => {
+ breakpointSize = 'sm';
+
+ expect(
+ canShowSubItems(),
+ ).toBeFalsy();
+ });
+ });
+});
diff --git a/spec/javascripts/groups/group_identicon_spec.js b/spec/javascripts/groups/group_identicon_spec.js
new file mode 100644
index 00000000000..66772327503
--- /dev/null
+++ b/spec/javascripts/groups/group_identicon_spec.js
@@ -0,0 +1,60 @@
+import Vue from 'vue';
+import groupIdenticonComponent from '~/groups/components/group_identicon.vue';
+import GroupsStore from '~/groups/stores/groups_store';
+import { group1 } from './mock_data';
+
+const createComponent = () => {
+ const Component = Vue.extend(groupIdenticonComponent);
+ const store = new GroupsStore();
+ const group = store.decorateGroup(group1);
+
+ return new Component({
+ propsData: {
+ entityId: group.id,
+ entityName: group.name,
+ },
+ }).$mount();
+};
+
+describe('GroupIdenticonComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ describe('computed', () => {
+ describe('identiconStyles', () => {
+ it('should return styles attribute value with `background-color` property', () => {
+ vm.entityId = 4;
+
+ expect(vm.identiconStyles).toBeDefined();
+ expect(vm.identiconStyles.indexOf('background-color: #E0F2F1;') > -1).toBeTruthy();
+ });
+
+ it('should return styles attribute value with `color` property', () => {
+ vm.entityId = 4;
+
+ expect(vm.identiconStyles).toBeDefined();
+ expect(vm.identiconStyles.indexOf('color: #555;') > -1).toBeTruthy();
+ });
+ });
+
+ describe('identiconTitle', () => {
+ it('should return first letter of entity title in uppercase', () => {
+ vm.entityName = 'dummy-group';
+
+ expect(vm.identiconTitle).toBeDefined();
+ expect(vm.identiconTitle).toBe('D');
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('should render identicon', () => {
+ expect(vm.$el.nodeName).toBe('DIV');
+ expect(vm.$el.classList.contains('identicon')).toBeTruthy();
+ expect(vm.$el.getAttribute('style').indexOf('background-color') > -1).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js
index aaffb56fa94..b14153dbbfa 100644
--- a/spec/javascripts/groups/groups_spec.js
+++ b/spec/javascripts/groups/groups_spec.js
@@ -64,6 +64,19 @@ describe('Groups Component', () => {
expect(lists[2].querySelector('#group-1120').textContent).toContain(groups.id1119.subGroups.id1120.name);
});
+ it('should render group identicon when group avatar is not present', () => {
+ const avatar = component.$el.querySelector('#group-12 .avatar-container .avatar');
+ expect(avatar.nodeName).toBe('DIV');
+ expect(avatar.classList.contains('identicon')).toBeTruthy();
+ expect(avatar.getAttribute('style').indexOf('background-color') > -1).toBeTruthy();
+ });
+
+ it('should render group avatar when group avatar is present', () => {
+ const avatar = component.$el.querySelector('#group-1120 .avatar-container .avatar');
+ expect(avatar.nodeName).toBe('IMG');
+ expect(avatar.classList.contains('identicon')).toBeFalsy();
+ });
+
it('should remove prefix of parent group', () => {
expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4');
});
diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js
index b3f5d791b89..5bb84b591f4 100644
--- a/spec/javascripts/groups/mock_data.js
+++ b/spec/javascripts/groups/mock_data.js
@@ -1,5 +1,5 @@
const group1 = {
- id: '12',
+ id: 12,
name: 'level1',
path: 'level1',
description: 'foo',
@@ -71,7 +71,7 @@ const group21 = {
path: 'chef',
description: 'foo',
visibility: 'public',
- avatar_url: null,
+ avatar_url: '/uploads/-/system/group/avatar/2/GitLab.png',
web_url: 'http://localhost:3000/groups/devops/chef',
group_path: '/devops/chef',
full_name: 'devops / chef',
diff --git a/spec/javascripts/lib/utils/ajax_cache_spec.js b/spec/javascripts/lib/utils/ajax_cache_spec.js
index 2c946802dcd..49971bd91e2 100644
--- a/spec/javascripts/lib/utils/ajax_cache_spec.js
+++ b/spec/javascripts/lib/utils/ajax_cache_spec.js
@@ -77,6 +77,15 @@ describe('AjaxCache', () => {
});
});
+ describe('override', () => {
+ it('overrides existing cache', () => {
+ AjaxCache.internalStorage.endpoint = 'existing-endpoint';
+ AjaxCache.override('endpoint', 'new-endpoint');
+
+ expect(AjaxCache.internalStorage.endpoint).toEqual('new-endpoint');
+ });
+ });
+
describe('retrieve', () => {
let ajaxSpy;
diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js
new file mode 100644
index 00000000000..850768f0e4f
--- /dev/null
+++ b/spec/javascripts/projects/project_new_spec.js
@@ -0,0 +1,127 @@
+import projectNew from '~/projects/project_new';
+
+describe('New Project', () => {
+ let $projectImportUrl;
+ let $projectPath;
+
+ beforeEach(() => {
+ setFixtures(`
+ <input id="project_import_url" />
+ <input id="project_path" />
+ `);
+
+ $projectImportUrl = $('#project_import_url');
+ $projectPath = $('#project_path');
+ });
+
+ describe('deriveProjectPathFromUrl', () => {
+ const dummyImportUrl = `${gl.TEST_HOST}/dummy/import/url.git`;
+
+ beforeEach(() => {
+ projectNew.bindEvents();
+ $projectPath.val('').keyup().val(dummyImportUrl);
+ });
+
+ it('does not change project path for disabled $projectImportUrl', () => {
+ $projectImportUrl.attr('disabled', true);
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual(dummyImportUrl);
+ });
+
+ describe('for enabled $projectImportUrl', () => {
+ beforeEach(() => {
+ $projectImportUrl.attr('disabled', false);
+ });
+
+ it('does not change project path if it is set by user', () => {
+ $projectPath.keyup();
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual(dummyImportUrl);
+ });
+
+ it('does not change project path for empty $projectImportUrl', () => {
+ $projectImportUrl.val('');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual(dummyImportUrl);
+ });
+
+ it('does not change project path for whitespace $projectImportUrl', () => {
+ $projectImportUrl.val(' ');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual(dummyImportUrl);
+ });
+
+ it('does not change project path for $projectImportUrl without slashes', () => {
+ $projectImportUrl.val('has-no-slash');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual(dummyImportUrl);
+ });
+
+ it('changes project path to last $projectImportUrl component', () => {
+ $projectImportUrl.val('/this/is/last');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('last');
+ });
+
+ it('ignores trailing slashes in $projectImportUrl', () => {
+ $projectImportUrl.val('/has/trailing/slash/');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('slash');
+ });
+
+ it('ignores fragment identifier in $projectImportUrl', () => {
+ $projectImportUrl.val('/this/has/a#fragment-identifier/');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('a');
+ });
+
+ it('ignores query string in $projectImportUrl', () => {
+ $projectImportUrl.val('/url/with?query=string');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('with');
+ });
+
+ it('ignores trailing .git in $projectImportUrl', () => {
+ $projectImportUrl.val('/repository.git');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('repository');
+ });
+
+ it('changes project path for HTTPS URL in $projectImportUrl', () => {
+ $projectImportUrl.val('https://username:password@gitlab.company.com/group/project.git');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('project');
+ });
+
+ it('changes project path for SSH URL in $projectImportUrl', () => {
+ $projectImportUrl.val('git@gitlab.com:gitlab-org/gitlab-ce.git');
+
+ projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+
+ expect($projectPath.val()).toEqual('gitlab-ce');
+ });
+ });
+ });
+});