diff options
Diffstat (limited to 'spec/javascripts')
30 files changed, 430 insertions, 333 deletions
diff --git a/spec/javascripts/boards/board_blank_state_spec.js b/spec/javascripts/boards/board_blank_state_spec.js index 47baf83512f..2ee3792dd65 100644 --- a/spec/javascripts/boards/board_blank_state_spec.js +++ b/spec/javascripts/boards/board_blank_state_spec.js @@ -1,4 +1,5 @@ /* global BoardService */ +/* global mockBoardService */ import Vue from 'vue'; import '~/boards/stores/boards_store'; import boardBlankState from '~/boards/components/board_blank_state'; @@ -12,7 +13,7 @@ describe('Boards blank state', () => { const Comp = Vue.extend(boardBlankState); gl.issueBoards.BoardsStore.create(); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); spyOn(gl.boardService, 'generateDefaultLists').and.callFake(() => new Promise((resolve, reject) => { if (fail) { diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js index 447b244c71f..83b13b06dc1 100644 --- a/spec/javascripts/boards/board_card_spec.js +++ b/spec/javascripts/boards/board_card_spec.js @@ -4,6 +4,7 @@ /* global listObj */ /* global boardsMockInterceptor */ /* global BoardService */ +/* global mockBoardService */ import Vue from 'vue'; import '~/boards/models/assignee'; @@ -14,13 +15,13 @@ import '~/boards/stores/boards_store'; import boardCard from '~/boards/components/board_card'; import './mock_data'; -describe('Issue card', () => { +describe('Board card', () => { let vm; beforeEach((done) => { Vue.http.interceptors.push(boardsMockInterceptor); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); gl.issueBoards.BoardsStore.create(); gl.issueBoards.BoardsStore.detail.issue = {}; diff --git a/spec/javascripts/boards/board_list_spec.js b/spec/javascripts/boards/board_list_spec.js index a89be911667..6bd00943a8f 100644 --- a/spec/javascripts/boards/board_list_spec.js +++ b/spec/javascripts/boards/board_list_spec.js @@ -3,6 +3,7 @@ /* global List */ /* global listObj */ /* global ListIssue */ +/* global mockBoardService */ import Vue from 'vue'; import _ from 'underscore'; import Sortable from 'vendor/Sortable'; @@ -24,7 +25,7 @@ describe('Board list component', () => { document.body.appendChild(el); Vue.http.interceptors.push(boardsMockInterceptor); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); gl.issueBoards.BoardsStore.create(); gl.IssueBoardsApp = new Vue(); @@ -32,6 +33,7 @@ describe('Board list component', () => { const list = new List(listObj); const issue = new ListIssue({ title: 'Testing', + id: 1, iid: 1, confidential: false, labels: [], diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js index eac2eecb6bc..02e6692dda8 100644 --- a/spec/javascripts/boards/board_new_issue_spec.js +++ b/spec/javascripts/boards/board_new_issue_spec.js @@ -2,6 +2,7 @@ /* global BoardService */ /* global List */ /* global listObj */ +/* global mockBoardService */ import Vue from 'vue'; import boardNewIssue from '~/boards/components/board_new_issue'; @@ -35,7 +36,7 @@ describe('Issue boards new issue form', () => { const BoardNewIssueComp = Vue.extend(boardNewIssue); Vue.http.interceptors.push(boardsMockInterceptor); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); gl.issueBoards.BoardsStore.create(); gl.IssueBoardsApp = new Vue(); diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js index 5ea160b7790..9e5b0bd3efe 100644 --- a/spec/javascripts/boards/boards_store_spec.js +++ b/spec/javascripts/boards/boards_store_spec.js @@ -4,6 +4,7 @@ /* global listObj */ /* global listObjDuplicate */ /* global ListIssue */ +/* global mockBoardService */ import Vue from 'vue'; import Cookies from 'js-cookie'; @@ -20,7 +21,7 @@ import './mock_data'; describe('Store', () => { beforeEach(() => { Vue.http.interceptors.push(boardsMockInterceptor); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); gl.issueBoards.BoardsStore.create(); spyOn(gl.boardService, 'moveIssue').and.callFake(() => new Promise((resolve) => { @@ -78,7 +79,7 @@ describe('Store', () => { it('persists new list', (done) => { gl.issueBoards.BoardsStore.new({ title: 'Test', - type: 'label', + list_type: 'label', label: { id: 1, title: 'Testing', @@ -210,6 +211,7 @@ describe('Store', () => { it('moves issue in list', (done) => { const issue = new ListIssue({ title: 'Testing', + id: 2, iid: 2, confidential: false, labels: [], diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js index c4e8966ad6c..8dacac20cad 100644 --- a/spec/javascripts/boards/components/board_spec.js +++ b/spec/javascripts/boards/components/board_spec.js @@ -1,7 +1,9 @@ +/* global mockBoardService */ import Vue from 'vue'; import '~/boards/services/board_service'; import '~/boards/components/board'; import '~/boards/models/list'; +import '../mock_data'; describe('Board component', () => { let vm; @@ -13,8 +15,12 @@ describe('Board component', () => { el = document.createElement('div'); document.body.appendChild(el); - // eslint-disable-next-line no-undef - gl.boardService = new BoardService('/', '/', 1); + gl.boardService = mockBoardService({ + boardsEndpoint: '/', + listsEndpoint: '/', + bulkUpdatePath: '/', + boardId: 1, + }); vm = new gl.issueBoards.Board({ propsData: { diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index 47aaa57e6b9..7d430ec35e2 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -37,6 +37,7 @@ describe('Issue card component', () => { list = listObj; issue = new ListIssue({ title: 'Testing', + id: 1, iid: 1, confidential: false, labels: [list.label], @@ -238,65 +239,63 @@ describe('Issue card component', () => { }); describe('labels', () => { - describe('exists', () => { - beforeEach((done) => { - component.issue.addLabel(label1); + beforeEach((done) => { + component.issue.addLabel(label1); - Vue.nextTick(() => done()); - }); + Vue.nextTick(() => done()); + }); - it('renders list label', () => { - expect( - component.$el.querySelectorAll('.label').length, - ).toBe(2); + it('renders list label', () => { + expect( + component.$el.querySelectorAll('.label').length, + ).toBe(2); + }); + + it('renders label', () => { + const nodes = []; + component.$el.querySelectorAll('.label').forEach((label) => { + nodes.push(label.title); }); - it('renders label', () => { - const nodes = []; - component.$el.querySelectorAll('.label').forEach((label) => { - nodes.push(label.title); - }); + expect( + nodes.includes(label1.description), + ).toBe(true); + }); - expect( - nodes.includes(label1.description), - ).toBe(true); - }); + it('sets label description as title', () => { + expect( + component.$el.querySelector('.label').getAttribute('title'), + ).toContain(label1.description); + }); - it('sets label description as title', () => { - expect( - component.$el.querySelector('.label').getAttribute('title'), - ).toContain(label1.description); + it('sets background color of button', () => { + const nodes = []; + component.$el.querySelectorAll('.label').forEach((label) => { + nodes.push(label.style.backgroundColor); }); - it('sets background color of button', () => { - const nodes = []; - component.$el.querySelectorAll('.label').forEach((label) => { - nodes.push(label.style.backgroundColor); - }); + expect( + nodes.includes(label1.color), + ).toBe(true); + }); - expect( - nodes.includes(label1.color), - ).toBe(true); - }); + it('does not render label if label does not have an ID', (done) => { + component.issue.addLabel(new ListLabel({ + title: 'closed', + })); - it('does not render label if label does not have an ID', (done) => { - component.issue.addLabel(new ListLabel({ - title: 'closed', - })); + Vue.nextTick() + .then(() => { + expect( + component.$el.querySelectorAll('.label').length, + ).toBe(2); + expect( + component.$el.textContent, + ).not.toContain('closed'); - Vue.nextTick() - .then(() => { - expect( - component.$el.querySelectorAll('.label').length, - ).toBe(2); - expect( - component.$el.textContent, - ).not.toContain('closed'); - - done(); - }) - .catch(done.fail); - }); + done(); + }) + .catch(done.fail); }); }); }); diff --git a/spec/javascripts/boards/issue_spec.js b/spec/javascripts/boards/issue_spec.js index cd1497bc5e6..022d286d5df 100644 --- a/spec/javascripts/boards/issue_spec.js +++ b/spec/javascripts/boards/issue_spec.js @@ -1,6 +1,7 @@ /* eslint-disable comma-dangle */ /* global BoardService */ /* global ListIssue */ +/* global mockBoardService */ import Vue from 'vue'; import '~/lib/utils/url_utility'; @@ -16,11 +17,12 @@ describe('Issue model', () => { let issue; beforeEach(() => { - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService(); gl.issueBoards.BoardsStore.create(); issue = new ListIssue({ title: 'Testing', + id: 1, iid: 1, confidential: false, labels: [{ diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js index db50829a276..d4627223a12 100644 --- a/spec/javascripts/boards/list_spec.js +++ b/spec/javascripts/boards/list_spec.js @@ -1,6 +1,7 @@ /* eslint-disable comma-dangle */ /* global boardsMockInterceptor */ /* global BoardService */ +/* global mockBoardService */ /* global List */ /* global ListIssue */ /* global listObj */ @@ -22,7 +23,9 @@ describe('List model', () => { beforeEach(() => { Vue.http.interceptors.push(boardsMockInterceptor); - gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.boardService = mockBoardService({ + bulkUpdatePath: '/test/issue-boards/board/1/lists', + }); gl.issueBoards.BoardsStore.create(); list = new List(listObj); @@ -92,6 +95,7 @@ describe('List model', () => { const listDup = new List(listObjDuplicate); const issue = new ListIssue({ title: 'Testing', + id: _.random(10000), iid: _.random(10000), confidential: false, labels: [list.label, listDup.label], @@ -118,6 +122,7 @@ describe('List model', () => { for (let i = 0; i < 30; i += 1) { list.issues.push(new ListIssue({ title: 'Testing', + id: _.random(10000) + i, iid: _.random(10000) + i, confidential: false, labels: [list.label], @@ -137,7 +142,7 @@ describe('List model', () => { it('does not increase page number if issue count is less than the page size', () => { list.issues.push(new ListIssue({ title: 'Testing', - iid: _.random(10000), + id: _.random(10000), confidential: false, labels: [list.label], assignees: [], @@ -156,7 +161,7 @@ describe('List model', () => { spyOn(gl.boardService, 'newIssue').and.returnValue(Promise.resolve({ json() { return { - iid: 42, + id: 42, }; }, })); @@ -165,14 +170,14 @@ describe('List model', () => { it('adds new issue to top of list', (done) => { list.issues.push(new ListIssue({ title: 'Testing', - iid: _.random(10000), + id: _.random(10000), confidential: false, labels: [list.label], assignees: [], })); const dummyIssue = new ListIssue({ title: 'new issue', - iid: _.random(10000), + id: _.random(10000), confidential: false, labels: [list.label], assignees: [], diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js index a64c3964ee3..0a93086985e 100644 --- a/spec/javascripts/boards/mock_data.js +++ b/spec/javascripts/boards/mock_data.js @@ -1,3 +1,4 @@ +/* global BoardService */ /* eslint-disable comma-dangle, no-unused-vars, quote-props */ const listObj = { @@ -28,19 +29,19 @@ const listObjDuplicate = { const BoardsMockData = { 'GET': { - '/test/issue-boards/board/1/lists{/id}/issues': { + '/test/boards/1{/id}/issues': { issues: [{ title: 'Testing', + id: 1, iid: 1, confidential: false, labels: [], assignees: [], }], - size: 1 } }, 'POST': { - '/test/issue-boards/board/1/lists{/id}': listObj + '/test/boards/1{/id}': listObj }, 'PUT': { '/test/issue-boards/board/1/lists{/id}': {} @@ -58,7 +59,22 @@ const boardsMockInterceptor = (request, next) => { })); }; +const mockBoardService = (opts = {}) => { + const boardsEndpoint = opts.boardsEndpoint || '/test/issue-boards/board'; + const listsEndpoint = opts.listsEndpoint || '/test/boards/1'; + const bulkUpdatePath = opts.bulkUpdatePath || ''; + const boardId = opts.boardId || '1'; + + return new BoardService({ + boardsEndpoint, + listsEndpoint, + bulkUpdatePath, + boardId, + }); +}; + window.listObj = listObj; window.listObjDuplicate = listObjDuplicate; window.BoardsMockData = BoardsMockData; window.boardsMockInterceptor = boardsMockInterceptor; +window.mockBoardService = mockBoardService; diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/javascripts/boards/modal_store_spec.js index 32e6d04df9f..7eecb58a4c3 100644 --- a/spec/javascripts/boards/modal_store_spec.js +++ b/spec/javascripts/boards/modal_store_spec.js @@ -18,6 +18,7 @@ describe('Modal store', () => { issue = new ListIssue({ title: 'Testing', + id: 1, iid: 1, confidential: false, labels: [], @@ -25,6 +26,7 @@ describe('Modal store', () => { }); issue2 = new ListIssue({ title: 'Testing', + id: 1, iid: 2, confidential: false, labels: [], diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js index a34cadec0ab..454f187ccbc 100644 --- a/spec/javascripts/commit/pipelines/pipelines_spec.js +++ b/spec/javascripts/commit/pipelines/pipelines_spec.js @@ -29,6 +29,7 @@ describe('Pipelines table in Commits and Merge requests', () => { propsData: { endpoint: 'endpoint', helpPagePath: 'foo', + autoDevopsHelpPath: 'foo', }, }).$mount(); }); @@ -64,6 +65,7 @@ describe('Pipelines table in Commits and Merge requests', () => { propsData: { endpoint: 'endpoint', helpPagePath: 'foo', + autoDevopsHelpPath: 'foo', }, }).$mount(); }); @@ -115,6 +117,7 @@ describe('Pipelines table in Commits and Merge requests', () => { propsData: { endpoint: 'endpoint', helpPagePath: 'foo', + autoDevopsHelpPath: 'foo', }, }).$mount(); element.appendChild(this.component.$el); @@ -136,6 +139,7 @@ describe('Pipelines table in Commits and Merge requests', () => { propsData: { endpoint: 'endpoint', helpPagePath: 'foo', + autoDevopsHelpPath: 'foo', }, }).$mount(); }); diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index 16ae649ee60..f209328dee1 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -411,4 +411,26 @@ describe('Filtered Search Manager', () => { expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual(false); }); }); + + describe('getAllParams', () => { + beforeEach(() => { + this.paramsArr = ['key=value', 'otherkey=othervalue']; + + initializeManager(); + }); + + it('correctly modifies params when custom modifier is passed', () => { + const modifedParams = manager.getAllParams.call({ + modifyUrlParams: paramsArr => paramsArr.reverse(), + }, [].concat(this.paramsArr)); + + expect(modifedParams[0]).toBe(this.paramsArr[1]); + }); + + it('does not modify params when no custom modifier is passed', () => { + const modifedParams = manager.getAllParams.call({}, this.paramsArr); + + expect(modifedParams[1]).toBe(this.paramsArr[1]); + }); + }); }); diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js index 4588bf3d971..f8b37c0edde 100644 --- a/spec/javascripts/fly_out_nav_spec.js +++ b/spec/javascripts/fly_out_nav_spec.js @@ -34,6 +34,8 @@ describe('Fly out sidebar navigation', () => { document.body.innerHTML = ''; breakpointSize = 'lg'; mousePos.length = 0; + + setSidebar(null); }); describe('calculateTop', () => { @@ -242,6 +244,32 @@ describe('Fly out sidebar navigation', () => { ).toBe('block'); }); + it('shows collapsed only sub-items if icon only sidebar', () => { + const subItems = el.querySelector('.sidebar-sub-level-items'); + const sidebar = document.createElement('div'); + sidebar.classList.add('sidebar-icons-only'); + subItems.classList.add('is-fly-out-only'); + + setSidebar(sidebar); + + showSubLevelItems(el); + + expect( + el.querySelector('.sidebar-sub-level-items').style.display, + ).toBe('block'); + }); + + it('does not show collapsed only sub-items if icon only sidebar', () => { + const subItems = el.querySelector('.sidebar-sub-level-items'); + subItems.classList.add('is-fly-out-only'); + + showSubLevelItems(el); + + expect( + subItems.style.display, + ).not.toBe('block'); + }); + it('sets transform of sub-items', () => { const subItems = el.querySelector('.sidebar-sub-level-items'); showSubLevelItems(el); @@ -283,10 +311,6 @@ describe('Fly out sidebar navigation', () => { }); describe('canShowActiveSubItems', () => { - afterEach(() => { - setSidebar(null); - }); - it('returns true by default', () => { expect( canShowActiveSubItems(el), diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 10fcc590c89..ca048123bf7 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -4,8 +4,11 @@ import '~/gl_dropdown'; import '~/lib/utils/common_utils'; import '~/lib/utils/url_utility'; -(() => { - const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; +describe('glDropdown', function describeDropdown() { + preloadFixtures('static/gl_dropdown.html.raw'); + loadJSONFixtures('projects.json'); + + const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item'; const SEARCH_INPUT_SELECTOR = '.dropdown-input-field'; const ITEM_SELECTOR = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES})`; const FOCUSED_ITEM_SELECTOR = `${ITEM_SELECTOR} a.is-focused`; @@ -39,187 +42,217 @@ import '~/lib/utils/url_utility'; remoteCallback = callback.bind({}, data); }; - describe('Dropdown', function describeDropdown() { - preloadFixtures('static/gl_dropdown.html.raw'); - loadJSONFixtures('projects.json'); - - function initDropDown(hasRemote, isFilterable, extraOpts = {}) { - const options = Object.assign({ - selectable: true, - filterable: isFilterable, - data: hasRemote ? remoteMock.bind({}, this.projectsData) : this.projectsData, - search: { - fields: ['name'] - }, - text: project => (project.name_with_namespace || project.name), - id: project => project.id, - }, extraOpts); - this.dropdownButtonElement = $('#js-project-dropdown', this.dropdownContainerElement).glDropdown(options); - } + function initDropDown(hasRemote, isFilterable, extraOpts = {}) { + const options = Object.assign({ + selectable: true, + filterable: isFilterable, + data: hasRemote ? remoteMock.bind({}, this.projectsData) : this.projectsData, + search: { + fields: ['name'] + }, + text: project => (project.name_with_namespace || project.name), + id: project => project.id, + }, extraOpts); + this.dropdownButtonElement = $('#js-project-dropdown', this.dropdownContainerElement).glDropdown(options); + } + + beforeEach(() => { + loadFixtures('static/gl_dropdown.html.raw'); + this.dropdownContainerElement = $('.dropdown.inline'); + this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement); + this.projectsData = getJSONFixture('projects.json'); + }); - beforeEach(() => { - loadFixtures('static/gl_dropdown.html.raw'); - this.dropdownContainerElement = $('.dropdown.inline'); - this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement); - this.projectsData = getJSONFixture('projects.json'); - }); + afterEach(() => { + $('body').unbind('keydown'); + this.dropdownContainerElement.unbind('keyup'); + }); - afterEach(() => { - $('body').unbind('keydown'); - this.dropdownContainerElement.unbind('keyup'); - }); + it('should open on click', () => { + initDropDown.call(this, false); + expect(this.dropdownContainerElement).not.toHaveClass('open'); + this.dropdownButtonElement.click(); + expect(this.dropdownContainerElement).toHaveClass('open'); + }); - it('should open on click', () => { - initDropDown.call(this, false); - expect(this.dropdownContainerElement).not.toHaveClass('open'); - this.dropdownButtonElement.click(); - expect(this.dropdownContainerElement).toHaveClass('open'); - }); + it('escapes HTML as text', () => { + this.projectsData[0].name_with_namespace = '<script>alert("testing");</script>'; - it('escapes HTML as text', () => { - this.projectsData[0].name_with_namespace = '<script>alert("testing");</script>'; + initDropDown.call(this, false); - initDropDown.call(this, false); + this.dropdownButtonElement.click(); - this.dropdownButtonElement.click(); + expect( + $('.dropdown-content li:first-child').text(), + ).toBe('<script>alert("testing");</script>'); + }); - expect( - $('.dropdown-content li:first-child').text(), - ).toBe('<script>alert("testing");</script>'); - }); + it('should output HTML when highlighting', () => { + this.projectsData[0].name_with_namespace = 'testing'; + $('.dropdown-input .dropdown-input-field').val('test'); - it('should output HTML when highlighting', () => { - this.projectsData[0].name_with_namespace = 'testing'; - $('.dropdown-input .dropdown-input-field').val('test'); + initDropDown.call(this, false, true, { + highlight: true, + }); - initDropDown.call(this, false, true, { - highlight: true, - }); + this.dropdownButtonElement.click(); - this.dropdownButtonElement.click(); + expect( + $('.dropdown-content li:first-child').text(), + ).toBe('testing'); - expect( - $('.dropdown-content li:first-child').text(), - ).toBe('testing'); + expect( + $('.dropdown-content li:first-child a').html(), + ).toBe('<b>t</b><b>e</b><b>s</b><b>t</b>ing'); + }); - expect( - $('.dropdown-content li:first-child a').html(), - ).toBe('<b>t</b><b>e</b><b>s</b><b>t</b>ing'); + describe('that is open', () => { + beforeEach(() => { + initDropDown.call(this, false, false); + this.dropdownButtonElement.click(); }); - describe('that is open', () => { - beforeEach(() => { - initDropDown.call(this, false, false); - this.dropdownButtonElement.click(); + it('should select a following item on DOWN keypress', () => { + expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0); + const randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 1)) + 0); + navigateWithKeys('down', randomIndex, () => { + expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1); + expect($(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused'); }); + }); - it('should select a following item on DOWN keypress', () => { - expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0); - const randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 1)) + 0); - navigateWithKeys('down', randomIndex, () => { + it('should select a previous item on UP keypress', () => { + expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0); + navigateWithKeys('down', (this.projectsData.length - 1), () => { + expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1); + const randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 2)) + 0); + navigateWithKeys('up', randomIndex, () => { expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1); - expect($(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused'); + expect($(`${ITEM_SELECTOR}:eq(${((this.projectsData.length - 2) - randomIndex)}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused'); }); }); + }); - it('should select a previous item on UP keypress', () => { - expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0); - navigateWithKeys('down', (this.projectsData.length - 1), () => { - expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1); - const randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 2)) + 0); - navigateWithKeys('up', randomIndex, () => { - expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1); - expect($(`${ITEM_SELECTOR}:eq(${((this.projectsData.length - 2) - randomIndex)}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused'); - }); + it('should click the selected item on ENTER keypress', () => { + expect(this.dropdownContainerElement).toHaveClass('open'); + const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0; + navigateWithKeys('down', randomIndex, () => { + spyOn(gl.utils, 'visitUrl').and.stub(); + navigateWithKeys('enter', null, () => { + expect(this.dropdownContainerElement).not.toHaveClass('open'); + const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement); + expect(link).toHaveClass('is-active'); + const linkedLocation = link.attr('href'); + if (linkedLocation && linkedLocation !== '#') expect(gl.utils.visitUrl).toHaveBeenCalledWith(linkedLocation); }); }); + }); - it('should click the selected item on ENTER keypress', () => { - expect(this.dropdownContainerElement).toHaveClass('open'); - const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0; - navigateWithKeys('down', randomIndex, () => { - spyOn(gl.utils, 'visitUrl').and.stub(); - navigateWithKeys('enter', null, () => { - expect(this.dropdownContainerElement).not.toHaveClass('open'); - const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement); - expect(link).toHaveClass('is-active'); - const linkedLocation = link.attr('href'); - if (linkedLocation && linkedLocation !== '#') expect(gl.utils.visitUrl).toHaveBeenCalledWith(linkedLocation); - }); - }); + it('should close on ESC keypress', () => { + expect(this.dropdownContainerElement).toHaveClass('open'); + this.dropdownContainerElement.trigger({ + type: 'keyup', + which: ARROW_KEYS.ESC, + keyCode: ARROW_KEYS.ESC }); + expect(this.dropdownContainerElement).not.toHaveClass('open'); + }); + }); - it('should close on ESC keypress', () => { - expect(this.dropdownContainerElement).toHaveClass('open'); - this.dropdownContainerElement.trigger({ - type: 'keyup', - which: ARROW_KEYS.ESC, - keyCode: ARROW_KEYS.ESC - }); - expect(this.dropdownContainerElement).not.toHaveClass('open'); + describe('opened and waiting for a remote callback', () => { + beforeEach(() => { + initDropDown.call(this, true, true); + this.dropdownButtonElement.click(); + }); + + it('should show loading indicator while search results are being fetched by backend', () => { + const dropdownMenu = document.querySelector('.dropdown-menu'); + + expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(true); + remoteCallback(); + expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(false); + }); + + it('should not focus search input while remote task is not complete', () => { + expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR)); + remoteCallback(); + expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); + }); + + it('should focus search input after remote task is complete', () => { + remoteCallback(); + expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); + }); + + it('should focus on input when opening for the second time after transition', () => { + remoteCallback(); + this.dropdownContainerElement.trigger({ + type: 'keyup', + which: ARROW_KEYS.ESC, + keyCode: ARROW_KEYS.ESC }); + this.dropdownButtonElement.click(); + this.dropdownContainerElement.trigger('transitionend'); + expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); }); + }); + + describe('input focus with array data', () => { + it('should focus input when passing array data to drop down', () => { + initDropDown.call(this, false, true); + this.dropdownButtonElement.click(); + this.dropdownContainerElement.trigger('transitionend'); + expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); + }); + }); + + it('should still have input value on close and restore', () => { + const $searchInput = $(SEARCH_INPUT_SELECTOR); + initDropDown.call(this, false, true); + $searchInput + .trigger('focus') + .val('g') + .trigger('input'); + expect($searchInput.val()).toEqual('g'); + this.dropdownButtonElement.trigger('hidden.bs.dropdown'); + $searchInput + .trigger('blur') + .trigger('focus'); + expect($searchInput.val()).toEqual('g'); + }); + + describe('renderItem', () => { + describe('without selected value', () => { + let dropdown; - describe('opened and waiting for a remote callback', () => { beforeEach(() => { - initDropDown.call(this, true, true); - this.dropdownButtonElement.click(); + const dropdownOptions = { + + }; + const $dropdownDiv = $('<div />'); + $dropdownDiv.glDropdown(dropdownOptions); + dropdown = $dropdownDiv.data('glDropdown'); }); - it('should show loading indicator while search results are being fetched by backend', () => { - const dropdownMenu = document.querySelector('.dropdown-menu'); + it('marks items without ID as active', () => { + const dummyData = { }; - expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(true); - remoteCallback(); - expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(false); - }); + const html = dropdown.renderItem(dummyData, null, null); - it('should not focus search input while remote task is not complete', () => { - expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR)); - remoteCallback(); - expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); + const link = html.querySelector('a'); + expect(link).toHaveClass('is-active'); }); - it('should focus search input after remote task is complete', () => { - remoteCallback(); - expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); - }); + it('does not mark items with ID as active', () => { + const dummyData = { + id: 'ea' + }; - it('should focus on input when opening for the second time after transition', () => { - remoteCallback(); - this.dropdownContainerElement.trigger({ - type: 'keyup', - which: ARROW_KEYS.ESC, - keyCode: ARROW_KEYS.ESC - }); - this.dropdownButtonElement.click(); - this.dropdownContainerElement.trigger('transitionend'); - expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); - }); - }); + const html = dropdown.renderItem(dummyData, null, null); - describe('input focus with array data', () => { - it('should focus input when passing array data to drop down', () => { - initDropDown.call(this, false, true); - this.dropdownButtonElement.click(); - this.dropdownContainerElement.trigger('transitionend'); - expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); + const link = html.querySelector('a'); + expect(link).not.toHaveClass('is-active'); }); }); - - it('should still have input value on close and restore', () => { - const $searchInput = $(SEARCH_INPUT_SELECTOR); - initDropDown.call(this, false, true); - $searchInput - .trigger('focus') - .val('g') - .trigger('input'); - expect($searchInput.val()).toEqual('g'); - this.dropdownButtonElement.trigger('hidden.bs.dropdown'); - $searchInput - .trigger('blur') - .trigger('focus'); - expect($searchInput.val()).toEqual('g'); - }); }); -})(); +}); diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 39065814bc2..583a3a74d77 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -42,7 +42,6 @@ describe('Issuable output', () => { initialDescriptionText: '', markdownPreviewPath: '/', markdownDocsPath: '/', - isConfidential: false, projectNamespace: '/', projectPath: '/', }, @@ -157,30 +156,6 @@ describe('Issuable output', () => { }); }); - it('reloads the page if the confidential status has changed', (done) => { - spyOn(gl.utils, 'visitUrl'); - spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { - resolve({ - json() { - return { - confidential: true, - web_url: location.pathname, - }; - }, - }); - })); - - vm.updateIssuable(); - - setTimeout(() => { - expect( - gl.utils.visitUrl, - ).toHaveBeenCalledWith(location.pathname); - - done(); - }); - }); - it('correctly updates issuable data', (done) => { spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { resolve(); diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index e982f23c87e..b45b0be804f 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -118,7 +118,7 @@ describe('Issue', function() { this.$triggeredButton = $btn; - this.$projectIssuesCounter = $('.issue_counter'); + this.$projectIssuesCounter = $('.issue_counter').first(); this.$projectIssuesCounter.text('1,001'); this.issueStateDeferred = new jQuery.Deferred(); diff --git a/spec/javascripts/monitoring/graph/legend_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index da2fbd26e23..2571b7ef869 100644 --- a/spec/javascripts/monitoring/graph/legend_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -28,7 +28,7 @@ const defaultValuesComponent = { currentDataIndex: 0, }; -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], defaultValuesComponent.graphWidth, defaultValuesComponent.graphHeight, defaultValuesComponent.graphHeightOffset); @@ -89,13 +89,12 @@ describe('GraphLegend', () => { expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2); }); - it('contains text to signal the usage, title and time', () => { + it('contains text to signal the usage, title and time with multiple time series', () => { const component = createComponent(defaultValuesComponent); const titles = component.$el.querySelectorAll('.legend-metric-title'); - expect(getTextFromNode(component, '.legend-metric-title').indexOf(component.legendTitle)).not.toEqual(-1); - expect(titles[0].textContent.indexOf('Title')).not.toEqual(-1); - expect(titles[1].textContent.indexOf('Series')).not.toEqual(-1); + expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1); + expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1); expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel); }); diff --git a/spec/javascripts/monitoring/monitoring_paths_spec.js b/spec/javascripts/monitoring/graph_path_spec.js index d39db945e17..a4844636d09 100644 --- a/spec/javascripts/monitoring/monitoring_paths_spec.js +++ b/spec/javascripts/monitoring/graph_path_spec.js @@ -1,10 +1,10 @@ import Vue from 'vue'; -import MonitoringPaths from '~/monitoring/components/monitoring_paths.vue'; +import GraphPath from '~/monitoring/components/graph_path.vue'; import createTimeSeries from '~/monitoring/utils/multiple_time_series'; import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from './mock_data'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringPaths); + const Component = Vue.extend(GraphPath); return new Component({ propsData, @@ -13,22 +13,23 @@ const createComponent = (propsData) => { const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], 428, 272, 120); +const firstTimeSeries = timeSeries[0]; describe('Monitoring Paths', () => { it('renders two paths to represent a line and the area underneath it', () => { const component = createComponent({ - generatedLinePath: timeSeries[0].linePath, - generatedAreaPath: timeSeries[0].areaPath, - lineColor: '#ccc', - areaColor: '#fff', + generatedLinePath: firstTimeSeries.linePath, + generatedAreaPath: firstTimeSeries.areaPath, + lineColor: firstTimeSeries.lineColor, + areaColor: firstTimeSeries.areaColor, }); const metricArea = component.$el.querySelector('.metric-area'); const metricLine = component.$el.querySelector('.metric-line'); - expect(metricArea.getAttribute('fill')).toBe('#fff'); - expect(metricArea.getAttribute('d')).toBe(timeSeries[0].areaPath); - expect(metricLine.getAttribute('stroke')).toBe('#ccc'); - expect(metricLine.getAttribute('d')).toBe(timeSeries[0].linePath); + expect(metricArea.getAttribute('fill')).toBe('#8fbce8'); + expect(metricArea.getAttribute('d')).toBe(firstTimeSeries.areaPath); + expect(metricLine.getAttribute('stroke')).toBe('#1f78d1'); + expect(metricLine.getAttribute('d')).toBe(firstTimeSeries.linePath); }); }); diff --git a/spec/javascripts/monitoring/graph_row_spec.js b/spec/javascripts/monitoring/graph_row_spec.js deleted file mode 100644 index 6a79d7c8f82..00000000000 --- a/spec/javascripts/monitoring/graph_row_spec.js +++ /dev/null @@ -1,62 +0,0 @@ -import Vue from 'vue'; -import GraphRow from '~/monitoring/components/graph_row.vue'; -import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins'; -import { deploymentData, convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from './mock_data'; - -const createComponent = (propsData) => { - const Component = Vue.extend(GraphRow); - - return new Component({ - propsData, - }).$mount(); -}; - -const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -describe('GraphRow', () => { - beforeEach(() => { - spyOn(MonitoringMixins.methods, 'formatDeployments').and.returnValue({}); - }); - describe('Computed props', () => { - it('bootstrapClass is set to col-md-6 when rowData is higher/equal to 2', () => { - const component = createComponent({ - rowData: convertedMetrics, - updateAspectRatio: false, - deploymentData, - }); - - expect(component.bootstrapClass).toEqual('col-md-6'); - }); - - it('bootstrapClass is set to col-md-12 when rowData is lower than 2', () => { - const component = createComponent({ - rowData: [convertedMetrics[0]], - updateAspectRatio: false, - deploymentData, - }); - - expect(component.bootstrapClass).toEqual('col-md-12'); - }); - }); - - it('has one column', () => { - const component = createComponent({ - rowData: convertedMetrics, - updateAspectRatio: false, - deploymentData, - }); - - expect(component.$el.querySelectorAll('.prometheus-svg-container').length) - .toEqual(component.rowData.length); - }); - - it('has two columns', () => { - const component = createComponent({ - rowData: convertedMetrics, - updateAspectRatio: false, - deploymentData, - }); - - expect(component.$el.querySelectorAll('.col-md-6').length) - .toEqual(component.rowData.length); - }); -}); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 3d399f2bb95..7ceab657464 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -6346,7 +6346,13 @@ export const singleRowMetricsMultipleSeries = [ } ] }, - ] + ], + 'when': [ + { + 'value': 'hundred(s)', + 'color': 'green', + }, + ], } ] }, diff --git a/spec/javascripts/monitoring/monitoring_store_spec.js b/spec/javascripts/monitoring/monitoring_store_spec.js index 20c1e6a0005..88aa7659275 100644 --- a/spec/javascripts/monitoring/monitoring_store_spec.js +++ b/spec/javascripts/monitoring/monitoring_store_spec.js @@ -5,10 +5,10 @@ describe('MonitoringStore', () => { this.store = new MonitoringStore(); this.store.storeMetrics(MonitoringMock.data); - it('contains one group that contains two queries sorted by priority in one row', () => { + it('contains one group that contains two queries sorted by priority', () => { expect(this.store.groups).toBeDefined(); expect(this.store.groups.length).toEqual(1); - expect(this.store.groups[0].metrics.length).toEqual(1); + expect(this.store.groups[0].metrics.length).toEqual(2); }); it('gets the metrics count for every group', () => { diff --git a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js index 3daf6bf82df..7e44a9ade9e 100644 --- a/spec/javascripts/monitoring/utils/multiple_time_series_spec.js +++ b/spec/javascripts/monitoring/utils/multiple_time_series_spec.js @@ -2,16 +2,17 @@ import createTimeSeries from '~/monitoring/utils/multiple_time_series'; import { convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from '../mock_data'; const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -const timeSeries = createTimeSeries(convertedMetrics[0].queries[0].result, 428, 272, 120); +const timeSeries = createTimeSeries(convertedMetrics[0].queries[0], 428, 272, 120); +const firstTimeSeries = timeSeries[0]; describe('Multiple time series', () => { it('createTimeSeries returned array contains an object for each element', () => { - expect(typeof timeSeries[0].linePath).toEqual('string'); - expect(typeof timeSeries[0].areaPath).toEqual('string'); - expect(typeof timeSeries[0].timeSeriesScaleX).toEqual('function'); - expect(typeof timeSeries[0].areaColor).toEqual('string'); - expect(typeof timeSeries[0].lineColor).toEqual('string'); - expect(timeSeries[0].values instanceof Array).toEqual(true); + expect(typeof firstTimeSeries.linePath).toEqual('string'); + expect(typeof firstTimeSeries.areaPath).toEqual('string'); + expect(typeof firstTimeSeries.timeSeriesScaleX).toEqual('function'); + expect(typeof firstTimeSeries.areaColor).toEqual('string'); + expect(typeof firstTimeSeries.lineColor).toEqual('string'); + expect(firstTimeSeries.values instanceof Array).toEqual(true); }); it('createTimeSeries returns an array', () => { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 8c5ad8914b0..3e791a31604 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -770,6 +770,20 @@ import '~/notes'; expect($tempNote.prop('nodeName')).toEqual('LI'); expect($tempNote.find('.timeline-content').hasClass('discussion')).toBeTruthy(); }); + + it('should return a escaped user name', () => { + const currentUserFullnameXSS = 'Foo <script>alert("XSS")</script>'; + const $tempNote = this.notes.createPlaceholderNote({ + formContent: sampleComment, + uniqueId, + isDiscussionNote: false, + currentUsername, + currentUserFullname: currentUserFullnameXSS, + currentUserAvatar, + }); + const $tempNoteHeader = $tempNote.find('.note-header'); + expect($tempNoteHeader.find('.hidden-xs').text().trim()).toEqual('Foo <script>alert("XSS")</script>'); + }); }); describe('createPlaceholderSystemNote', () => { diff --git a/spec/javascripts/pipelines/pipeline_url_spec.js b/spec/javascripts/pipelines/pipeline_url_spec.js index 3c4b20a5f06..256fdbe743c 100644 --- a/spec/javascripts/pipelines/pipeline_url_spec.js +++ b/spec/javascripts/pipelines/pipeline_url_spec.js @@ -16,6 +16,7 @@ describe('Pipeline Url Component', () => { path: 'foo', flags: {}, }, + autoDevopsHelpPath: 'foo', }, }).$mount(); @@ -30,6 +31,7 @@ describe('Pipeline Url Component', () => { path: 'foo', flags: {}, }, + autoDevopsHelpPath: 'foo', }, }).$mount(); @@ -50,6 +52,7 @@ describe('Pipeline Url Component', () => { path: '/', }, }, + autoDevopsHelpPath: 'foo', }; const component = new PipelineUrlComponent({ @@ -73,6 +76,7 @@ describe('Pipeline Url Component', () => { path: 'foo', flags: {}, }, + autoDevopsHelpPath: 'foo', }, }).$mount(); @@ -91,6 +95,7 @@ describe('Pipeline Url Component', () => { stuck: true, }, }, + autoDevopsHelpPath: 'foo', }, }).$mount(); @@ -98,4 +103,26 @@ describe('Pipeline Url Component', () => { expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain('yaml invalid'); expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck'); }); + + it('should render a badge for autodevops', () => { + const component = new PipelineUrlComponent({ + propsData: { + pipeline: { + id: 1, + path: 'foo', + flags: { + latest: true, + yaml_errors: true, + stuck: true, + auto_devops: true, + }, + }, + autoDevopsHelpPath: 'foo', + }, + }).$mount(); + + expect( + component.$el.querySelector('.js-pipeline-url-autodevops').textContent.trim(), + ).toEqual('Auto DevOps'); + }); }); diff --git a/spec/javascripts/pipelines/pipelines_table_row_spec.js b/spec/javascripts/pipelines/pipelines_table_row_spec.js index 7ce39dca112..d7456a48bc1 100644 --- a/spec/javascripts/pipelines/pipelines_table_row_spec.js +++ b/spec/javascripts/pipelines/pipelines_table_row_spec.js @@ -9,7 +9,7 @@ describe('Pipelines Table Row', () => { el: document.querySelector('.test-dom-element'), propsData: { pipeline, - service: {}, + autoDevopsHelpPath: 'foo', }, }).$mount(); }; diff --git a/spec/javascripts/pipelines/pipelines_table_spec.js b/spec/javascripts/pipelines/pipelines_table_spec.js index 3afe89c8db4..4f5eb42eb35 100644 --- a/spec/javascripts/pipelines/pipelines_table_spec.js +++ b/spec/javascripts/pipelines/pipelines_table_spec.js @@ -22,6 +22,7 @@ describe('Pipelines Table', () => { component = new PipelinesTableComponent({ propsData: { pipelines: [], + autoDevopsHelpPath: 'foo', }, }).$mount(); }); @@ -47,6 +48,7 @@ describe('Pipelines Table', () => { const component = new PipelinesTableComponent({ propsData: { pipelines: [], + autoDevopsHelpPath: 'foo', }, }).$mount(); expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(0); @@ -58,6 +60,7 @@ describe('Pipelines Table', () => { const component = new PipelinesTableComponent({ propsData: { pipelines: [pipeline], + autoDevopsHelpPath: 'foo', }, }).$mount(); diff --git a/spec/javascripts/projects_dropdown/components/projects_list_search_spec.js b/spec/javascripts/projects_dropdown/components/projects_list_search_spec.js index 59fc2dedba5..67f8a8946c2 100644 --- a/spec/javascripts/projects_dropdown/components/projects_list_search_spec.js +++ b/spec/javascripts/projects_dropdown/components/projects_list_search_spec.js @@ -43,7 +43,7 @@ describe('ProjectsListSearchComponent', () => { expect(vm.listEmptyMessage).toBe('Something went wrong on our end.'); vm.searchFailed = false; - expect(vm.listEmptyMessage).toBe('No projects matched your query'); + expect(vm.listEmptyMessage).toBe('Sorry, no projects matched your search'); }); }); }); diff --git a/spec/javascripts/projects_dropdown/components/search_spec.js b/spec/javascripts/projects_dropdown/components/search_spec.js index f2a23e33325..24d8a00b254 100644 --- a/spec/javascripts/projects_dropdown/components/search_spec.js +++ b/spec/javascripts/projects_dropdown/components/search_spec.js @@ -94,7 +94,7 @@ describe('SearchComponent', () => { expect(vm.$el.classList.contains('search-input-container')).toBeTruthy(); expect(vm.$el.classList.contains('hidden-xs')).toBeTruthy(); expect(inputEl).not.toBe(null); - expect(inputEl.getAttribute('placeholder')).toBe('Search projects'); + expect(inputEl.getAttribute('placeholder')).toBe('Search your projects'); expect(vm.$el.querySelector('.search-icon')).toBeDefined(); }); }); diff --git a/spec/javascripts/user_callout_spec.js b/spec/javascripts/user_callout_spec.js index 28d0c7dcd99..69cb93bd850 100644 --- a/spec/javascripts/user_callout_spec.js +++ b/spec/javascripts/user_callout_spec.js @@ -33,4 +33,17 @@ describe('UserCallout', function () { this.userCalloutBtn.click(); expect(Cookies.get(USER_CALLOUT_COOKIE)).toBe('true'); }); + + describe('Sets cookie with setCalloutPerProject', () => { + beforeEach(() => { + spyOn(Cookies, 'set').and.callFake(() => {}); + document.querySelector('.user-callout').setAttribute('data-project-path', 'foo/bar'); + this.userCallout = new UserCallout({ setCalloutPerProject: true }); + }); + + it('sets a cookie when the user clicks the close button', () => { + this.userCalloutBtn.click(); + expect(Cookies.set).toHaveBeenCalledWith('user_callout_dismissed', 'true', Object({ expires: 365, path: 'foo/bar' })); + }); + }); }); |