diff options
author | Clement Ho <ClemMakesApps@gmail.com> | 2017-03-30 04:45:33 +0300 |
---|---|---|
committer | Clement Ho <ClemMakesApps@gmail.com> | 2017-03-30 04:45:33 +0300 |
commit | 6bd0f8edb2d94b91eb70b0eeae1a2c4a12d6182b (patch) | |
tree | 385dfe3f00d55e73170419cea3df317537adfd4c /spec | |
parent | ea5ed498952c492b36a8b974e33e17953ebd4430 (diff) |
Add vue specsissue-board-cards-redesign
Diffstat (limited to 'spec')
-rw-r--r-- | spec/javascripts/boards/issue_card_header_spec.js | 148 | ||||
-rw-r--r-- | spec/javascripts/boards/issue_card_inner_spec.js | 126 | ||||
-rw-r--r-- | spec/javascripts/boards/issue_card_labels_spec.js | 227 | ||||
-rw-r--r-- | spec/javascripts/boards/issue_card_spec.js | 192 |
4 files changed, 501 insertions, 192 deletions
diff --git a/spec/javascripts/boards/issue_card_header_spec.js b/spec/javascripts/boards/issue_card_header_spec.js new file mode 100644 index 00000000000..77718095550 --- /dev/null +++ b/spec/javascripts/boards/issue_card_header_spec.js @@ -0,0 +1,148 @@ +import Vue from 'vue'; +import headerComponent from '~/boards/components/issue_card_header'; + +const propData = { + confidential: true, + title: 'this is a title', + issueId: 23, + assignee: { + username: 'batman', + name: 'Bruce Wayne', + avatar: 'https://batman.gravatar', + }, + issueLinkBase: 'linkBase', + rootPath: 'rootPath', +}; + +const createComponent = (propsData) => { + const Component = Vue.extend(headerComponent); + + return new Component({ + el: document.createElement('div'), + propsData, + }); +}; + +describe('IssueCardHeader', () => { + describe('props', () => { + const props = headerComponent.props; + + it('should have confidential prop', () => { + const { confidential } = props; + const ConfidentialClass = confidential.type; + + expect(confidential).toBeDefined(); + expect(new ConfidentialClass() instanceof Boolean).toBeTruthy(); + expect(confidential.required).toBeTruthy(); + }); + + it('should have title prop', () => { + const { title } = props; + const TitleClass = title.type; + + expect(title).toBeDefined(); + expect(new TitleClass() instanceof String).toBeTruthy(); + expect(title.required).toBeTruthy(); + }); + + it('should have issueId prop', () => { + const { issueId } = props; + const IssueIdClass = issueId.type; + + expect(issueId).toBeDefined(); + expect(new IssueIdClass() instanceof Number).toBeTruthy(); + expect(issueId.required).toBeTruthy(); + }); + + it('should have assignee prop', () => { + const { assignee } = props; + + expect(assignee).toBeDefined(); + expect(assignee instanceof Object).toBeTruthy(); + expect(assignee.required).toBeTruthy(); + }); + + it('should have issueLinkBase prop', () => { + const { issueLinkBase } = props; + const IssueLinkBaseClass = issueLinkBase.type; + + expect(issueLinkBase).toBeDefined(); + expect(new IssueLinkBaseClass() instanceof String).toBeTruthy(); + expect(issueLinkBase.required).toBeTruthy(); + }); + + it('should have rootPath prop', () => { + const { rootPath } = props; + const RootPathClass = rootPath.type; + + expect(rootPath).toBeDefined(); + expect(new RootPathClass() instanceof String).toBeTruthy(); + expect(rootPath.required).toBeTruthy(); + }); + }); + + describe('computed', () => { + describe('hasAssignee', () => { + it('should return whether there is an assignee', () => { + const data = Object.assign({}, propData); + + let vm = createComponent(data); + expect(vm.hasAssignee).toEqual(true); + + data.assignee = {}; + vm = createComponent(data); + expect(vm.hasAssignee).toEqual(false); + }); + }); + }); + + describe('template', () => { + it('should have correct elements', () => { + const el = createComponent(propData).$el; + expect(el.tagName).toEqual('DIV'); + expect(el.classList.contains('card-header')).toEqual(true); + + const confidentialIcon = el.querySelector('.confidential-icon'); + expect(confidentialIcon.tagName).toEqual('I'); + expect(confidentialIcon.classList.contains('fa')).toEqual(true); + expect(confidentialIcon.classList.contains('fa-eye-slash')).toEqual(true); + + const cardTitle = el.querySelector('.card-title'); + expect(cardTitle.tagName).toEqual('H4'); + + const cardTitleLink = cardTitle.querySelector('a'); + expect(cardTitleLink.getAttribute('href')).toEqual(`${propData.issueLinkBase}/${propData.issueId}`); + expect(cardTitleLink.getAttribute('title')).toEqual(propData.title); + expect(cardTitleLink.innerText).toEqual(propData.title); + + const cardNumber = cardTitle.querySelector('.card-number'); + expect(cardNumber.tagName).toEqual('SPAN'); + expect(cardNumber.innerText).toEqual(`#${propData.issueId}`); + + const cardAssignee = el.querySelector('.card-assignee'); + expect(cardAssignee.tagName).toEqual('A'); + expect(cardAssignee.getAttribute('href')).toEqual(`${propData.rootPath}${propData.assignee.username}`); + expect(cardAssignee.getAttribute('title')).toEqual(`Assigned to ${propData.assignee.name}`); + + const cardAssigneeImage = cardAssignee.querySelector('img'); + expect(cardAssigneeImage.getAttribute('src')).toEqual(propData.assignee.avatar); + expect(cardAssigneeImage.getAttribute('alt')).toEqual(`Avatar for ${propData.assignee.name}`); + }); + + it('should not display confidential icon if confidential is false', () => { + const data = Object.assign({}, propData); + data.confidential = false; + const el = createComponent(data).$el; + + expect(el.querySelector('.confidential-icon')).toEqual(null); + }); + + it('should not render assignee if there is no assignee', () => { + const data = Object.assign({}, propData); + data.assignee = {}; + const el = createComponent(data).$el; + + expect(el.querySelector('.card-assignee')).toEqual(null); + }); + }); +}); diff --git a/spec/javascripts/boards/issue_card_inner_spec.js b/spec/javascripts/boards/issue_card_inner_spec.js new file mode 100644 index 00000000000..d7dc5a71f4c --- /dev/null +++ b/spec/javascripts/boards/issue_card_inner_spec.js @@ -0,0 +1,126 @@ +import Vue from 'vue'; +import cardComponent from '~/boards/components/issue_card_inner'; +import headerComponent from '~/boards/components/issue_card_header'; +import labelsComponent from '~/boards/components/issue_card_labels'; + +const propData = { + issue: { + title: 'title', + id: 1, + confidential: true, + assignee: {}, + labels: [], + }, + issueLinkBase: 'issueLinkBase', + list: {}, + rootPath: 'rootPath', + updateFilters: false, +}; + +const createComponent = (componentName, propsData) => { + const Component = Vue.extend.call(Vue, componentName); + + return new Component({ + el: document.createElement('div'), + propsData, + }); +}; + +describe('IssueCardInner', () => { + describe('props', () => { + const props = cardComponent.props; + + it('should have issue prop', () => { + const { issue } = props; + + expect(issue).toBeDefined(); + expect(issue instanceof Object).toBeTruthy(); + expect(issue.required).toBeTruthy(); + }); + + it('should have issueLinkBase prop', () => { + const { issueLinkBase } = props; + const IssueLinkBaseClass = issueLinkBase.type; + + expect(issueLinkBase).toBeDefined(); + expect(new IssueLinkBaseClass() instanceof String).toBeTruthy(); + expect(issueLinkBase.required).toBeTruthy(); + }); + + it('should have list prop', () => { + const { list } = props; + + expect(list).toBeDefined(); + expect(list instanceof Object).toBeTruthy(); + expect(list.required).toBeFalsy(); + }); + + it('should have rootPath prop', () => { + const { rootPath } = props; + const RootPathClass = rootPath.type; + + expect(rootPath).toBeDefined(); + expect(new RootPathClass() instanceof String).toBeTruthy(); + expect(rootPath.required).toBeTruthy(); + }); + + it('should have updateFilters prop', () => { + const { updateFilters } = props; + const UpdateFiltersClass = updateFilters.type; + + expect(updateFilters).toBeDefined(); + expect(new UpdateFiltersClass() instanceof Boolean).toBeTruthy(); + expect(updateFilters.required).toBeFalsy(); + expect(updateFilters.default).toBeFalsy(); + }); + }); + + describe('computed', () => { + describe('assignee', () => { + it('should return assignee object by default', () => { + const vm = createComponent(cardComponent, propData); + expect(vm.assignee instanceof Object).toBeTruthy(); + }); + + it('should return empty object if assignee is false', () => { + const data = Object.assign({}, propData); + data.issue.assignee = false; + + const vm = createComponent(cardComponent, data); + expect(vm.assignee instanceof Object).toBeTruthy(); + }); + }); + }); + + describe('components', () => { + it('should have components added', () => { + expect(cardComponent.components['issue-card-header']).toBeDefined(); + expect(cardComponent.components['issue-card-labels']).toBeDefined(); + }); + }); + + describe('template', () => { + it('should have correct elements', () => { + const vm = createComponent(cardComponent, propData); + const el = vm.$el; + + const headerComponentEl = createComponent(headerComponent, { + confidential: propData.issue.confidential, + title: propData.issue.title, + issueId: propData.issue.id, + assignee: vm.assignee, + issueLinkBase: propData.issueLinkBase, + rootPath: propData.rootPath, + }).$el; + + const labelsComponentEl = createComponent(labelsComponent, { + labels: propData.issue.labels, + list: propData.list, + updateFilters: propData.updateFilters, + }).$el; + + const contents = `${headerComponentEl.innerHTML}${labelsComponentEl.innerHTML}`; + expect(el.innerHTML.indexOf(contents) !== -1).toEqual(true); + }); + }); +}); diff --git a/spec/javascripts/boards/issue_card_labels_spec.js b/spec/javascripts/boards/issue_card_labels_spec.js new file mode 100644 index 00000000000..50b1ee18423 --- /dev/null +++ b/spec/javascripts/boards/issue_card_labels_spec.js @@ -0,0 +1,227 @@ +import Vue from 'vue'; +import labelsComponent from '~/boards/components/issue_card_labels'; +import eventHub from '~/boards/eventhub'; +import '~/boards/stores/boards_store'; + +const propData = { + labels: [{ + color: 'rgb(0, 0, 0)', + textColor: 'rgb(255, 255, 255)', + description: '', + id: 1, + title: 'Frontend', + }, { + color: 'rgb(255, 255, 255)', + textColor: 'rgb(0, 0, 0)', + description: '', + id: 2, + title: 'Community Contribution', + }], + list: { + color: 'rgb(0, 0, 0)', + id: 3, + title: 'bug', + }, + updateFilters: true, +}; + +const createComponent = (propsData) => { + const Component = Vue.extend(labelsComponent); + + return new Component({ + el: document.createElement('div'), + propsData, + }); +}; + +describe('IssueCardLabels', () => { + describe('props', () => { + const props = labelsComponent.props; + + it('should have labels prop', () => { + const { labels } = props; + const LabelsClass = labels.type; + + expect(labels).toBeDefined(); + expect(new LabelsClass() instanceof Array).toBeTruthy(); + expect(labels.required).toBeTruthy(); + }); + + it('should have list prop', () => { + const { list } = props; + + expect(list).toBeDefined(); + expect(list instanceof Object).toBeTruthy(); + expect(list.required).toBeFalsy(); + }); + + it('should have updateFilters prop', () => { + const { updateFilters } = props; + const UpdateFiltersClass = updateFilters.type; + + expect(updateFilters).toBeDefined(); + expect(new UpdateFiltersClass() instanceof Boolean).toBeTruthy(); + expect(updateFilters.required).toBeFalsy(); + expect(updateFilters.default).toBeFalsy(); + }); + }); + + describe('methods', () => { + describe('showLabel', () => { + it('should return true if there is no list', () => { + const data = Object.assign({}, propData); + data.list = null; + const vm = createComponent(data); + + expect(vm.showLabel()).toEqual(true); + }); + + it('should return true if there is a list and no list.label', () => { + const vm = createComponent(propData); + + expect(vm.showLabel()).toEqual(true); + }); + + it('should return true if list.label.id does not match label.id', () => { + const data = Object.assign({}, propData); + data.list.label = { + id: 100, + }; + const vm = createComponent(data); + + const showLabel = vm.showLabel({ + id: 1, + }); + + expect(showLabel).toEqual(true); + }); + }); + + describe('filterByLabel', () => { + it('should not continue if there is no updateFilters set', () => { + const data = Object.assign({}, propData); + data.updateFilters = null; + + const spy = spyOn(gl.issueBoards.BoardsStore.filter.path, 'split').and.callThrough(); + const vm = createComponent(data); + vm.filterByLabel({ title: 'title' }, { currentTarget: '' }); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('should hide tooltip', () => { + const spy = spyOn($.fn, 'tooltip').and.callFake(() => {}); + const vm = createComponent(propData); + + vm.filterByLabel({ title: 'title' }, { currentTarget: '' }); + expect(spy).toHaveBeenCalledWith('hide'); + }); + + it('should add/remove label to BoardsStore filter path', () => { + const originalPath = gl.issueBoards.BoardsStore.filter.path; + const vm = createComponent(propData); + + const label = { title: 'special' }; + vm.filterByLabel(label, { currentTarget: '' }); + + expect(gl.issueBoards.BoardsStore.filter.path).toEqual(`${originalPath}&label_name[]=${label.title}`); + + vm.filterByLabel(label, { currentTarget: '' }); + expect(gl.issueBoards.BoardsStore.filter.path).toEqual(originalPath); + }); + + it('should encode label title', () => { + const originalPath = gl.issueBoards.BoardsStore.filter.path; + const vm = createComponent(propData); + + const label = { title: '!@#$%^ &*()' }; + vm.filterByLabel(label, { currentTarget: '' }); + + expect(gl.issueBoards.BoardsStore.filter.path).toEqual(`${originalPath}&label_name[]=${encodeURIComponent(label.title)}`); + }); + + it('should updateFiltersUrl', () => { + spyOn(gl.issueBoards.BoardsStore, 'updateFiltersUrl').and.callFake(() => {}); + + const vm = createComponent(propData); + vm.filterByLabel({ title: 'title' }, { currentTarget: '' }); + + expect(gl.issueBoards.BoardsStore.updateFiltersUrl).toHaveBeenCalled(); + expect(gl.issueBoards.BoardsStore.updateFiltersUrl.calls.count()).toEqual(1); + }); + + it('should emit updateTokens to eventHub', (done) => { + const vm = createComponent(propData); + spyOn(eventHub, '$emit').and.callFake((message) => { + expect(message).toEqual('updateTokens'); + done(); + }); + + vm.filterByLabel({ title: 'title' }, { currentTarget: '' }); + }); + }); + + describe('labelStyle', () => { + it('should return style object with backgroundColor and color', () => { + const data = { + color: '#000000', + textColor: '#FFFFFF', + }; + + const vm = createComponent(propData); + const style = vm.labelStyle(data); + expect(style.backgroundColor).toEqual(data.color); + expect(style.color).toEqual(data.textColor); + }); + }); + }); + + describe('template', () => { + it('should have correct elements', () => { + const vm = createComponent(propData); + const el = vm.$el; + spyOn(vm, 'filterByLabel').and.callThrough(); + + expect(el.tagName).toEqual('DIV'); + expect(el.classList.contains('card-footer')).toEqual(true); + + const labels = el.querySelectorAll('button'); + expect(labels.length).toEqual(2); + + const firstLabel = labels[0]; + expect(firstLabel.getAttribute('type')).toEqual('button'); + expect(firstLabel.textContent.trim()).toEqual(propData.labels[0].title); + expect(firstLabel.getAttribute('title')).toEqual(propData.labels[0].description); + expect(firstLabel.style.backgroundColor).toEqual(propData.labels[0].color); + expect(firstLabel.style.color).toEqual(propData.labels[0].textColor); + + firstLabel.click(); + expect(vm.filterByLabel).toHaveBeenCalled(); + expect(vm.filterByLabel.calls.count()).toEqual(1); + vm.filterByLabel.calls.reset(); + + const secondLabel = labels[1]; + expect(secondLabel.getAttribute('type')).toEqual('button'); + expect(secondLabel.textContent.trim()).toEqual(propData.labels[1].title); + expect(secondLabel.getAttribute('title')).toEqual(propData.labels[1].description); + expect(secondLabel.style.backgroundColor).toEqual(propData.labels[1].color); + expect(secondLabel.style.color).toEqual(propData.labels[1].textColor); + + secondLabel.click(); + expect(vm.filterByLabel).toHaveBeenCalled(); + expect(vm.filterByLabel.calls.count()).toEqual(1); + }); + + it('should not display label if showLabel is false', () => { + const data = Object.assign({}, propData); + data.list.label = { + id: 1, + }; + const vm = createComponent(data); + const el = vm.$el; + + const labels = el.querySelectorAll('button'); + expect(labels.length).toEqual(1); + }); + }); +}); diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js deleted file mode 100644 index 1a5e9e9fd07..00000000000 --- a/spec/javascripts/boards/issue_card_spec.js +++ /dev/null @@ -1,192 +0,0 @@ -/* global ListUser */ -/* global ListLabel */ -/* global listObj */ -/* global ListIssue */ - -import Vue from 'vue'; - -require('~/boards/models/issue'); -require('~/boards/models/label'); -require('~/boards/models/list'); -require('~/boards/models/user'); -require('~/boards/stores/boards_store'); -require('~/boards/components/issue_card_inner'); -require('./mock_data'); - -describe('Issue card component', () => { - const user = new ListUser({ - id: 1, - name: 'testing 123', - username: 'test', - avatar: 'test_image', - }); - const label1 = new ListLabel({ - id: 3, - title: 'testing 123', - color: 'blue', - text_color: 'white', - description: 'test', - }); - let component; - let issue; - let list; - - beforeEach(() => { - setFixtures('<div class="test-container"></div>'); - - list = listObj; - issue = new ListIssue({ - title: 'Testing', - iid: 1, - confidential: false, - labels: [list.label], - }); - - component = new Vue({ - el: document.querySelector('.test-container'), - data() { - return { - list, - issue, - issueLinkBase: '/test', - rootPath: '/', - }; - }, - components: { - 'issue-card': gl.issueBoards.IssueCardInner, - }, - template: ` - <issue-card - :issue="issue" - :list="list" - :issue-link-base="issueLinkBase" - :root-path="rootPath"></issue-card> - `, - }); - }); - - it('renders issue title', () => { - expect( - component.$el.querySelector('.card-title').textContent, - ).toContain(issue.title); - }); - - it('includes issue base in link', () => { - expect( - component.$el.querySelector('.card-title a').getAttribute('href'), - ).toContain('/test'); - }); - - it('includes issue title on link', () => { - expect( - component.$el.querySelector('.card-title a').getAttribute('title'), - ).toBe(issue.title); - }); - - it('does not render confidential icon', () => { - expect( - component.$el.querySelector('.fa-eye-flash'), - ).toBeNull(); - }); - - it('renders confidential icon', (done) => { - component.issue.confidential = true; - - setTimeout(() => { - expect( - component.$el.querySelector('.confidential-icon'), - ).not.toBeNull(); - done(); - }, 0); - }); - - it('renders issue ID with #', () => { - expect( - component.$el.querySelector('.card-number').textContent, - ).toContain(`#${issue.id}`); - }); - - describe('assignee', () => { - it('does not render assignee', () => { - expect( - component.$el.querySelector('.card-assignee'), - ).toBeNull(); - }); - - describe('exists', () => { - beforeEach((done) => { - component.issue.assignee = user; - - setTimeout(() => { - done(); - }, 0); - }); - - it('renders assignee', () => { - expect( - component.$el.querySelector('.card-assignee'), - ).not.toBeNull(); - }); - - it('sets title', () => { - expect( - component.$el.querySelector('.card-assignee').getAttribute('title'), - ).toContain(`Assigned to ${user.name}`); - }); - - it('sets users path', () => { - expect( - component.$el.querySelector('.card-assignee').getAttribute('href'), - ).toBe('/test'); - }); - - it('renders avatar', () => { - expect( - component.$el.querySelector('.card-assignee img'), - ).not.toBeNull(); - }); - }); - }); - - describe('labels', () => { - it('does not render any', () => { - expect( - component.$el.querySelector('.label'), - ).toBeNull(); - }); - - describe('exists', () => { - beforeEach((done) => { - component.issue.addLabel(label1); - - setTimeout(() => { - done(); - }, 0); - }); - - it('does not render list label', () => { - expect( - component.$el.querySelectorAll('.label').length, - ).toBe(1); - }); - - it('renders label', () => { - expect( - component.$el.querySelector('.label').textContent, - ).toContain(label1.title); - }); - - it('sets label description as title', () => { - expect( - component.$el.querySelector('.label').getAttribute('title'), - ).toContain(label1.description); - }); - - it('sets background color of button', () => { - expect( - component.$el.querySelector('.label').style.backgroundColor, - ).toContain(label1.color); - }); - }); - }); -}); |