diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-10 12:08:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-10 12:08:56 +0300 |
commit | b4ded0ba7b4d2cdbed5b1f331cf2083a25ee4d7c (patch) | |
tree | 6694fa9d8f3e226597cc01dfb8e3e07b50ae85b6 /spec/frontend | |
parent | 2aaef94c80937d9d188f7b9cbbad2dcd1508c3c1 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
5 files changed, 267 insertions, 4 deletions
diff --git a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js new file mode 100644 index 00000000000..ff0b005f441 --- /dev/null +++ b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js @@ -0,0 +1,109 @@ +import { mount } from '@vue/test-utils'; +import BlobHeaderViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue'; +import { + RICH_BLOB_VIEWER, + RICH_BLOB_VIEWER_TITLE, + SIMPLE_BLOB_VIEWER, + SIMPLE_BLOB_VIEWER_TITLE, +} from '~/blob/components/constants'; +import { GlButtonGroup, GlButton } from '@gitlab/ui'; +import { Blob } from './mock_data'; + +describe('Blob Header Viewer Switcher', () => { + let wrapper; + + function createComponent(props = {}) { + wrapper = mount(BlobHeaderViewerSwitcher, { + propsData: { + blob: Object.assign({}, Blob, props), + }, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + describe('intiialization', () => { + it('is initialized with rich viewer as preselected when richViewer exists', () => { + createComponent(); + expect(wrapper.vm.viewer).toBe(RICH_BLOB_VIEWER); + }); + + it('is initialized with simple viewer as preselected when richViewer does not exists', () => { + createComponent({ richViewer: null }); + expect(wrapper.vm.viewer).toBe(SIMPLE_BLOB_VIEWER); + }); + }); + + describe('rendering', () => { + let btnGroup; + let buttons; + + beforeEach(() => { + createComponent(); + btnGroup = wrapper.find(GlButtonGroup); + buttons = wrapper.findAll(GlButton); + }); + + it('renders gl-button-group component', () => { + expect(btnGroup.exists()).toBe(true); + }); + + it('renders exactly 2 buttons with predefined actions', () => { + expect(buttons.length).toBe(2); + [SIMPLE_BLOB_VIEWER_TITLE, RICH_BLOB_VIEWER_TITLE].forEach((title, i) => { + expect(buttons.at(i).attributes('title')).toBe(title); + }); + }); + }); + + describe('viewer changes', () => { + let buttons; + let simpleBtn; + let richBtn; + + beforeEach(() => { + createComponent(); + buttons = wrapper.findAll(GlButton); + simpleBtn = buttons.at(0); + richBtn = buttons.at(1); + }); + + it('does not switch the viewer if the selected one is already active', () => { + jest.spyOn(wrapper.vm, '$emit'); + + expect(wrapper.vm.viewer).toBe(RICH_BLOB_VIEWER); + richBtn.vm.$emit('click'); + expect(wrapper.vm.viewer).toBe(RICH_BLOB_VIEWER); + expect(wrapper.vm.$emit).not.toHaveBeenCalled(); + }); + + it('emits an event when a Simple Viewer button is clicked', () => { + jest.spyOn(wrapper.vm, '$emit'); + + simpleBtn.vm.$emit('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.vm.viewer).toBe(SIMPLE_BLOB_VIEWER); + expect(wrapper.vm.$emit).toHaveBeenCalledWith('switch-viewer', SIMPLE_BLOB_VIEWER); + }); + }); + + it('emits an event when a Rich Viewer button is clicked', () => { + jest.spyOn(wrapper.vm, '$emit'); + + wrapper.setData({ viewer: SIMPLE_BLOB_VIEWER }); + + return wrapper.vm + .$nextTick() + .then(() => { + richBtn.vm.$emit('click'); + }) + .then(() => { + expect(wrapper.vm.viewer).toBe(RICH_BLOB_VIEWER); + expect(wrapper.vm.$emit).toHaveBeenCalledWith('switch-viewer', RICH_BLOB_VIEWER); + }); + }); + }); +}); diff --git a/spec/frontend/boards/components/issue_card_inner_scoped_label_spec.js b/spec/frontend/boards/components/issue_card_inner_scoped_label_spec.js new file mode 100644 index 00000000000..7389cb14ecb --- /dev/null +++ b/spec/frontend/boards/components/issue_card_inner_scoped_label_spec.js @@ -0,0 +1,43 @@ +import Vue from 'vue'; +import mountComponent from 'helpers/vue_mount_component_helper'; +import IssueCardInnerScopedLabel from '~/boards/components/issue_card_inner_scoped_label.vue'; + +describe('IssueCardInnerScopedLabel Component', () => { + let vm; + const Component = Vue.extend(IssueCardInnerScopedLabel); + const props = { + label: { title: 'Foo::Bar', description: 'Some Random Description' }, + labelStyle: { background: 'white', color: 'black' }, + scopedLabelsDocumentationLink: '/docs-link', + }; + const createComponent = () => mountComponent(Component, { ...props }); + + beforeEach(() => { + vm = createComponent(); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render label title', () => { + expect(vm.$el.querySelector('.color-label').textContent.trim()).toEqual('Foo::Bar'); + }); + + it('should render question mark symbol', () => { + expect(vm.$el.querySelector('.fa-question-circle')).not.toBeNull(); + }); + + it('should render label style provided', () => { + const node = vm.$el.querySelector('.color-label'); + + expect(node.style.background).toEqual(props.labelStyle.background); + expect(node.style.color).toEqual(props.labelStyle.color); + }); + + it('should render the docs link', () => { + expect(vm.$el.querySelector('a.scoped-label').href).toContain( + props.scopedLabelsDocumentationLink, + ); + }); +}); diff --git a/spec/frontend/boards/components/issue_due_date_spec.js b/spec/frontend/boards/components/issue_due_date_spec.js new file mode 100644 index 00000000000..68e26b68f04 --- /dev/null +++ b/spec/frontend/boards/components/issue_due_date_spec.js @@ -0,0 +1,65 @@ +import Vue from 'vue'; +import dateFormat from 'dateformat'; +import IssueDueDate from '~/boards/components/issue_due_date.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Issue Due Date component', () => { + let vm; + let date; + const Component = Vue.extend(IssueDueDate); + const createComponent = (dueDate = new Date()) => + mountComponent(Component, { date: dateFormat(dueDate, 'yyyy-mm-dd', true) }); + + beforeEach(() => { + date = new Date(); + vm = createComponent(); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render "Today" if the due date is today', () => { + const timeContainer = vm.$el.querySelector('time'); + + expect(timeContainer.textContent.trim()).toEqual('Today'); + }); + + it('should render "Yesterday" if the due date is yesterday', () => { + date.setDate(date.getDate() - 1); + vm = createComponent(date); + + expect(vm.$el.querySelector('time').textContent.trim()).toEqual('Yesterday'); + }); + + it('should render "Tomorrow" if the due date is one day from now', () => { + date.setDate(date.getDate() + 1); + vm = createComponent(date); + + expect(vm.$el.querySelector('time').textContent.trim()).toEqual('Tomorrow'); + }); + + it('should render day of the week if due date is one week away', () => { + date.setDate(date.getDate() + 5); + vm = createComponent(date); + + expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, 'dddd')); + }); + + it('should render month and day for other dates', () => { + date.setDate(date.getDate() + 17); + vm = createComponent(date); + const today = new Date(); + const isDueInCurrentYear = today.getFullYear() === date.getFullYear(); + const format = isDueInCurrentYear ? 'mmm d' : 'mmm d, yyyy'; + + expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, format)); + }); + + it('should contain the correct `.text-danger` css class for overdue issue', () => { + date.setDate(date.getDate() - 17); + vm = createComponent(date); + + expect(vm.$el.querySelector('time').classList.contains('text-danger')).toEqual(true); + }); +}); diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js index 9cf73d54d9b..b632b461eb9 100644 --- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js +++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js @@ -62,6 +62,7 @@ describe('ErrorTrackingList', () => { sortByField: jest.fn(), fetchPaginatedResults: jest.fn(), updateStatus: jest.fn(), + removeIgnoredResolvedErrors: jest.fn(), }; const state = { @@ -221,6 +222,8 @@ describe('ErrorTrackingList', () => { }); describe('When the ignore button on an error is clicked', () => { + const ignoreErrorButton = () => wrapper.find({ ref: 'ignoreError' }); + beforeEach(() => { store.state.list.loading = false; store.state.list.errors = errorsList; @@ -235,20 +238,30 @@ describe('ErrorTrackingList', () => { }); it('sends the "ignored" status and error ID', () => { - wrapper.find({ ref: 'ignoreError' }).trigger('click'); + ignoreErrorButton().trigger('click'); expect(actions.updateStatus).toHaveBeenCalledWith( expect.anything(), { endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`, - redirectUrl: '/error_tracking', status: 'ignored', }, undefined, ); }); + + it('calls an action to remove the item from the list', () => { + ignoreErrorButton().trigger('click'); + expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith( + expect.anything(), + '1', + undefined, + ); + }); }); describe('When the resolve button on an error is clicked', () => { + const resolveErrorButton = () => wrapper.find({ ref: 'resolveError' }); + beforeEach(() => { store.state.list.loading = false; store.state.list.errors = errorsList; @@ -263,17 +276,25 @@ describe('ErrorTrackingList', () => { }); it('sends "resolved" status and error ID', () => { - wrapper.find({ ref: 'resolveError' }).trigger('click'); + resolveErrorButton().trigger('click'); expect(actions.updateStatus).toHaveBeenCalledWith( expect.anything(), { endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`, - redirectUrl: '/error_tracking', status: 'resolved', }, undefined, ); }); + + it('calls an action to remove the item from the list', () => { + resolveErrorButton().trigger('click'); + expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith( + expect.anything(), + '1', + undefined, + ); + }); }); describe('When error tracking is disabled and user is not allowed to enable it', () => { diff --git a/spec/frontend/error_tracking/store/list/mutation_spec.js b/spec/frontend/error_tracking/store/list/mutation_spec.js index 44a75b6aa1f..65f11aeeda1 100644 --- a/spec/frontend/error_tracking/store/list/mutation_spec.js +++ b/spec/frontend/error_tracking/store/list/mutation_spec.js @@ -5,6 +5,7 @@ import * as types from '~/error_tracking/store/list/mutation_types'; const ADD_RECENT_SEARCH = mutations[types.ADD_RECENT_SEARCH]; const CLEAR_RECENT_SEARCHES = mutations[types.CLEAR_RECENT_SEARCHES]; const LOAD_RECENT_SEARCHES = mutations[types.LOAD_RECENT_SEARCHES]; +const REMOVE_IGNORED_RESOLVED_ERRORS = mutations[types.REMOVE_IGNORED_RESOLVED_ERRORS]; describe('Error tracking mutations', () => { describe('SET_ERRORS', () => { @@ -114,5 +115,29 @@ describe('Error tracking mutations', () => { expect(localStorage.getItem).toHaveBeenCalledWith('recent-searches/project/errors.json'); }); }); + + describe('REMOVE_IGNORED_RESOLVED_ERRORS', () => { + it('removes ignored or resolved errors from list', () => { + state.errors = [ + { + id: 1, + status: 'unresolved', + }, + { + id: 2, + status: 'ignored', + }, + { + id: 3, + status: 'unresolved', + }, + ]; + const ignoredError = state.errors[2].id; + + REMOVE_IGNORED_RESOLVED_ERRORS(state, ignoredError); + + expect(state.errors).not.toContain(ignoredError); + }); + }); }); }); |