diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-08-07 13:09:50 +0300 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-08-07 13:09:50 +0300 |
commit | 3b9012871da7dbf6d4f5463654c7c478012e694e (patch) | |
tree | 0dfd072107d486a85de73b3ae4016d4f4d13d04a /spec/javascripts | |
parent | 25c9b5b531c5dfe08f9dc9d075589a30465fa318 (diff) | |
parent | 03b816f3e845c9b25d3588336fc1616238465deb (diff) |
Merge branch 'master' into zj-project-templates
* master: (623 commits)
Fix issues with pdf-js dependencies
fix missing changelog entries for security release on 2017-01-23
Update top bar issues icon
Fix pipeline icon in contextual nav for projects
Since mysql is not a priority anymore, test it less
Fix order of CI lint ace editor loading
Add container registry and spam logs icons
Fix different Markdown styles
Backport to CE for:
Make new dropdown dividers full width
Fix spec
Fix spec
Fix spec
Bump GITLAB_SHELL_VERSION and GITALY_VERSION to support unhiding refs
Add changelog
Install yarn via apt in update guides
Use long curl options
fix
Add a spec for concurrent process
Remove monkey-patched Array.prototype.first() and last() methods
...
Diffstat (limited to 'spec/javascripts')
28 files changed, 681 insertions, 44 deletions
diff --git a/spec/javascripts/abuse_reports_spec.js b/spec/javascripts/abuse_reports_spec.js index 069d857eab6..13cab81dd60 100644 --- a/spec/javascripts/abuse_reports_spec.js +++ b/spec/javascripts/abuse_reports_spec.js @@ -6,10 +6,10 @@ import '~/abuse_reports'; const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw'; const MAX_MESSAGE_LENGTH = 500; - let messages; + let $messages; const assertMaxLength = $message => expect($message.text().length).toEqual(MAX_MESSAGE_LENGTH); - const findMessage = searchText => messages.filter( + const findMessage = searchText => $messages.filter( (index, element) => element.innerText.indexOf(searchText) > -1, ).first(); @@ -18,7 +18,7 @@ import '~/abuse_reports'; beforeEach(function () { loadFixtures(FIXTURE); this.abuseReports = new global.AbuseReports(); - messages = $('.abuse-reports .message'); + $messages = $('.abuse-reports .message'); }); it('should truncate long messages', () => { diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 1518ae68b0d..46e072a8ebb 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import 'jquery'; import 'jquery-ujs'; import '~/ajax_loading_spinner'; 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/extensions/array_spec.js b/spec/javascripts/extensions/array_spec.js deleted file mode 100644 index b1b81b4efc2..00000000000 --- a/spec/javascripts/extensions/array_spec.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable space-before-function-paren, no-var */ - -import '~/extensions/array'; - -(function() { - describe('Array extensions', function() { - describe('first', function() { - return it('returns the first item', function() { - var arr; - arr = [0, 1, 2, 3, 4, 5]; - return expect(arr.first()).toBe(0); - }); - }); - describe('last', function() { - return it('returns the last item', function() { - var arr; - arr = [0, 1, 2, 3, 4, 5]; - return expect(arr.last()).toBe(5); - }); - }); - }); -}).call(window); diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js index f55726379f3..b1b3d43f241 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/dropdown_utils'; import '~/filtered_search/filtered_search_tokenizer'; import '~/filtered_search/filtered_search_dropdown_manager'; @@ -191,6 +190,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_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js index 9e2076dc383..5c7e9115aac 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_visual_tokens'; import '~/filtered_search/filtered_search_tokenizer'; import '~/filtered_search/filtered_search_dropdown_manager'; diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js index 1a7631994b4..69b424c3af5 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_token_keys'; describe('Filtered Search Token Keys', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js index e4a15c83c23..585bea9b499 100644 --- a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_token_keys'; import '~/filtered_search/filtered_search_tokenizer'; 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/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index 45909d4e70e..3daeb91b1e2 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -135,10 +135,10 @@ describe('IntegrationSettingsForm', () => { integrationSettingsForm.testSettings(formData); - deferred.resolve({ error: true, message: errorMessage }); + deferred.resolve({ error: true, message: errorMessage, service_response: 'some error' }); const $flashContainer = $('.flash-container'); - expect($flashContainer.find('.flash-text').text()).toEqual(errorMessage); + expect($flashContainer.find('.flash-text').text()).toEqual('Test failed. some error'); expect($flashContainer.find('.flash-action')).toBeDefined(); expect($flashContainer.find('.flash-action').text()).toEqual('Save anyway'); }); 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/lib/utils/sticky_spec.js b/spec/javascripts/lib/utils/sticky_spec.js new file mode 100644 index 00000000000..c3ee3ef9825 --- /dev/null +++ b/spec/javascripts/lib/utils/sticky_spec.js @@ -0,0 +1,52 @@ +import { isSticky } from '~/lib/utils/sticky'; + +describe('sticky', () => { + const el = { + offsetTop: 0, + classList: {}, + }; + + beforeEach(() => { + el.offsetTop = 0; + el.classList.add = jasmine.createSpy('spy'); + el.classList.remove = jasmine.createSpy('spy'); + }); + + describe('classList.remove', () => { + it('does not call classList.remove when stuck', () => { + isSticky(el, 0, 0); + + expect( + el.classList.remove, + ).not.toHaveBeenCalled(); + }); + + it('calls classList.remove when not stuck', () => { + el.offsetTop = 10; + isSticky(el, 0, 0); + + expect( + el.classList.remove, + ).toHaveBeenCalledWith('is-stuck'); + }); + }); + + describe('classList.add', () => { + it('calls classList.add when stuck', () => { + isSticky(el, 0, 0); + + expect( + el.classList.add, + ).toHaveBeenCalledWith('is-stuck'); + }); + + it('does not call classList.add when not stuck', () => { + el.offsetTop = 10; + isSticky(el, 0, 0); + + expect( + el.classList.add, + ).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/pdf/index_spec.js b/spec/javascripts/pdf/index_spec.js index f661fae5fe2..bebed432f91 100644 --- a/spec/javascripts/pdf/index_spec.js +++ b/spec/javascripts/pdf/index_spec.js @@ -1,8 +1,8 @@ /* eslint-disable import/no-unresolved */ import Vue from 'vue'; -import { PDFJS } from 'pdfjs-dist'; -import workerSrc from 'vendor/pdf.worker'; +import { PDFJS } from 'vendor/pdf'; +import workerSrc from 'vendor/pdf.worker.min'; import PDFLab from '~/pdf/index.vue'; import pdf from '../fixtures/blob/pdf/test.pdf'; diff --git a/spec/javascripts/pdf/page_spec.js b/spec/javascripts/pdf/page_spec.js index ac76ebbfbe6..ac5b21e8f6c 100644 --- a/spec/javascripts/pdf/page_spec.js +++ b/spec/javascripts/pdf/page_spec.js @@ -1,8 +1,8 @@ /* eslint-disable import/no-unresolved */ import Vue from 'vue'; -import pdfjsLib from 'pdfjs-dist'; -import workerSrc from 'vendor/pdf.worker'; +import pdfjsLib from 'vendor/pdf'; +import workerSrc from 'vendor/pdf.worker.min'; import PageComponent from '~/pdf/page/index.vue'; import testPDF from '../fixtures/blob/pdf/test.pdf'; diff --git a/spec/javascripts/projects/project_import_gitlab_project_spec.js b/spec/javascripts/projects/project_import_gitlab_project_spec.js new file mode 100644 index 00000000000..2f1aae109e3 --- /dev/null +++ b/spec/javascripts/projects/project_import_gitlab_project_spec.js @@ -0,0 +1,25 @@ +import projectImportGitlab from '~/projects/project_import_gitlab_project'; + +describe('Import Gitlab project', () => { + let projectName; + beforeEach(() => { + projectName = 'project'; + window.history.pushState({}, null, `?path=${projectName}`); + + setFixtures(` + <input class="js-path-name" /> + `); + + projectImportGitlab.bindEvents(); + }); + + afterEach(() => { + window.history.pushState({}, null, ''); + }); + + describe('path name', () => { + it('should fill in the project name derived from the previously filled project name', () => { + expect(document.querySelector('.js-path-name').value).toEqual(projectName); + }); + }); +}); 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'); + }); + }); + }); +}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js index d4b200875df..ab8a3f6c64c 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js @@ -10,6 +10,7 @@ const deploymentMockData = [ url: '/root/acets-review-apps/environments/15', stop_url: '/root/acets-review-apps/environments/15/stop', metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics', + metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics', external_url: 'http://diplo.', external_url_formatted: 'diplo.', deployed_at: '2017-03-22T22:44:42.258Z', diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js index 2c3d0ddff28..6adcbc73ed7 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js @@ -3,6 +3,7 @@ import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widge import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; const url = '/root/acets-review-apps/environments/15/deployments/1/metrics'; +const monitoringUrl = '/root/acets-review-apps/environments/15/metrics'; const metricsMockData = { success: true, @@ -39,6 +40,7 @@ const createComponent = () => { el: document.createElement('div'), propsData: { metricsUrl: url, + metricsMonitoringUrl: monitoringUrl, memoryMetrics: [], deploymentTime: 0, hasMetrics: false, |