Commit d7db7920 authored by Mike Greiling's avatar Mike Greiling

Merge branch '51712-new-line-before-expect-ee' into 'master'

3. enable jasmine/new-line-before-expect

See merge request gitlab-org/gitlab-ee!7873
parents 8b077edc b2b3df49
......@@ -37,5 +37,4 @@ rules:
- devDependencies:
- ee/spec/**/*.js
# Temporarily disabled to facilitate an upgrade to eslint-plugin-jasmine
jasmine/new-line-before-expect: off
jasmine/prefer-toHaveBeenCalledWith: off
......@@ -37,7 +37,9 @@ describe('AddGitlabSlackApplication', () => {
vm.$el.querySelector('.js-popup-button').click();
vm.$nextTick()
.then(() => expect(vm.$el.querySelector('.js-popup')).toBeDefined())
.then(() => {
expect(vm.$el.querySelector('.js-popup')).toBeDefined()
})
.then(done)
.catch(done.fail);
});
......@@ -50,7 +52,9 @@ describe('AddGitlabSlackApplication', () => {
vm.$nextTick()
.then(() => vm.$el.querySelector('.js-popup-button').click())
.then(vm.$nextTick)
.then(() => expect(vm.$el.querySelector('.js-popup')).toBeNull())
.then(() => {
expect(vm.$el.querySelector('.js-popup')).toBeNull()
})
.then(done)
.catch(done.fail);
});
......@@ -64,7 +68,9 @@ describe('AddGitlabSlackApplication', () => {
vm.popupOpen = true;
vm.$nextTick()
.then(() => expect(vm.$el.querySelector('.js-project-select')).toBeDefined())
.then(() => {
expect(vm.$el.querySelector('.js-project-select')).toBeDefined()
})
.then(done)
.catch(done.fail);
});
......@@ -120,7 +126,9 @@ describe('AddGitlabSlackApplication', () => {
.then(() => vm.$el.querySelector('.js-add-button').click())
.then(vm.$nextTick)
.then(addToSlackPromise)
.then(() => expect(redirectTo).toHaveBeenCalledWith(redirectLink))
.then(() => {
expect(redirectTo).toHaveBeenCalledWith(redirectLink)
})
.then(done)
.catch(done.fail);
});
......
......@@ -45,6 +45,7 @@ describe('Approvals Body Component', () => {
describe('approvalsRequiredStringified', () => {
it('should display the correct string for 1 possible approver', () => {
const correctText = 'Requires 1 more approval by';
expect(vm.approvalsRequiredStringified).toBe(correctText);
});
......
......@@ -43,6 +43,7 @@ describe('Approvals Footer Component', () => {
it('should correctly set showUnapproveButton when the user can unapprove', () => {
expect(vm.showUnapproveButton).toBeTruthy();
vm.mr.state = 'merged';
expect(vm.showUnapproveButton).toBeFalsy();
});
......@@ -66,6 +67,7 @@ describe('Approvals Footer Component', () => {
Vue.nextTick(() => {
const memberImage = document.querySelector('.approvers-list img');
expect(memberImage.src).toMatch(/dummy\.jpg$/);
done();
});
......
......@@ -35,12 +35,14 @@ describe('board_form.vue', () => {
it('initializes `board.labels` as empty array when `label.isAny` is `true`', () => {
const labelIsAny = { isAny: true };
vm.handleLabelClick(labelIsAny);
expect(Array.isArray(vm.board.labels)).toBe(true);
expect(vm.board.labels.length).toBe(0);
});
it('adds provided `label` to board.labels', () => {
vm.handleLabelClick(label);
expect(vm.board.labels.length).toBe(1);
expect(vm.board.labels[0].id).toBe(label.id);
vm.handleLabelClick(label);
......@@ -50,6 +52,7 @@ describe('board_form.vue', () => {
const label2 = Object.assign({}, label, { id: 2 });
vm.handleLabelClick(label);
vm.handleLabelClick(label2);
expect(vm.board.labels.length).toBe(1);
expect(vm.board.labels[0].id).toBe(label2.id);
});
......
......@@ -39,6 +39,7 @@ describe('AssigneesListItem', () => {
const assignee = mockAssigneesList[0];
vm.handleItemClick();
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee);
});
});
......@@ -57,6 +58,7 @@ describe('AssigneesListItem', () => {
expect(
buttonEl.querySelector('.avatar-container.s32 img.avatar.s32').getAttribute('src'),
).toBe(assignee.avatar_url);
expect(buttonEl.querySelector('.dropdown-user-details').innerText).toContain(assignee.name);
expect(
buttonEl.querySelector('.dropdown-user-details .dropdown-light-content').innerText,
......
......@@ -96,6 +96,7 @@ describe('BoardListSelector', () => {
expect(vm.store.findList('title', assignee.name)).not.toBeDefined();
vm.handleItemClick(assignee);
expect(vm.store.new).toHaveBeenCalledWith(jasmine.any(Object));
});
});
......
......@@ -30,6 +30,7 @@ describe('ListContainer', () => {
describe('filteredItems', () => {
it('returns assignees list as it is when `query` is empty', () => {
vm.query = '';
expect(vm.filteredItems.length).toBe(mockAssigneesList.length);
});
......@@ -37,6 +38,7 @@ describe('ListContainer', () => {
const assignee = mockAssigneesList[0];
vm.query = assignee.name;
expect(vm.filteredItems.length).toBe(1);
expect(vm.filteredItems[0].name).toBe(assignee.name);
});
......@@ -45,6 +47,7 @@ describe('ListContainer', () => {
const assignee = mockAssigneesList[0];
vm.query = assignee.username;
expect(vm.filteredItems.length).toBe(1);
expect(vm.filteredItems[0].username).toBe(assignee.username);
});
......@@ -56,6 +59,7 @@ describe('ListContainer', () => {
it('sets value of param `query` to component prop `query`', () => {
const query = 'foobar';
vm.handleSearch(query);
expect(vm.query).toBe(query);
});
});
......@@ -66,6 +70,7 @@ describe('ListContainer', () => {
const assignee = mockAssigneesList[0];
vm.handleItemClick(assignee);
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee);
});
});
......
......@@ -32,6 +32,7 @@ describe('ListContent', () => {
const assignee = mockAssigneesList[0];
vm.handleItemClick(assignee);
expect(vm.$emit).toHaveBeenCalledWith('onItemSelect', assignee);
});
});
......
......@@ -28,6 +28,7 @@ describe('ListFilter', () => {
vm.query = query;
vm.handleInputChange();
expect(vm.$emit).toHaveBeenCalledWith('onSearchInput', query);
});
});
......@@ -38,6 +39,7 @@ describe('ListFilter', () => {
vm.query = 'foobar';
vm.handleInputClear();
expect(vm.query).toBe('');
expect(vm.handleInputChange).toHaveBeenCalled();
});
......@@ -71,6 +73,7 @@ describe('ListFilter', () => {
it('renders search input element', () => {
const inputEl = vm.$el.querySelector('input.dropdown-input-field');
expect(inputEl).not.toBeNull();
expect(inputEl.getAttribute('placeholder')).toBe('Search');
});
......
......@@ -45,6 +45,7 @@ describe('VariableList (EE features)', () => {
// Check for the correct default in the new row
const $environmentInput = $wrapper.find('.js-row:last-child').find('input[name="variables[variables_attributes][][environment_scope]"]');
expect($environmentInput.val()).toBe('*');
})
.then(done)
......@@ -60,6 +61,7 @@ describe('VariableList (EE features)', () => {
getSetTimeoutPromise()
.then(() => {
const $dropdownItemsBeforeRemove = $row.find('.js-variable-environment-dropdown-wrapper .dropdown-content a');
expect($dropdownItemsBeforeRemove.length).toBe(2);
expect($dropdownItemsBeforeRemove[0].textContent.trim()).toBe('someenv');
expect($dropdownItemsBeforeRemove[1].textContent.trim()).toBe('* (All environments)');
......@@ -70,6 +72,7 @@ describe('VariableList (EE features)', () => {
})
.then(() => {
const $dropdownItemsAfterRemove = $row.find('.js-variable-environment-dropdown-wrapper .dropdown-content a');
expect($dropdownItemsAfterRemove.length).toBe(1);
expect($dropdownItemsAfterRemove[0].textContent.trim()).toBe('* (All environments)');
})
......
......@@ -42,6 +42,7 @@ describe('epicHeader', () => {
it('should render status badge', () => {
const badgeEl = vm.$el.querySelector('.issuable-status-box');
const badgeIconEl = badgeEl.querySelector('svg use');
expect(badgeEl).not.toBe(null);
expect(badgeEl.innerText.trim()).toBe('Open');
expect(badgeIconEl.getAttribute('xlink:href')).toContain('issue-open-m');
......@@ -50,6 +51,7 @@ describe('epicHeader', () => {
it('should render `Close epic` button when `isEpicOpen` & `canUpdate` props are true', () => {
vm.isEpicOpen = true;
const closeButtonEl = vm.$el.querySelector('.js-issuable-actions .js-btn-epic-action');
expect(closeButtonEl).not.toBe(null);
expect(closeButtonEl.innerText.trim()).toBe('Close epic');
});
......@@ -58,11 +60,13 @@ describe('epicHeader', () => {
describe('statusIcon', () => {
it('returns `issue-open-m` when `isEpicOpen` prop is true', () => {
vm.isEpicOpen = true;
expect(vm.statusIcon).toBe('issue-open-m');
});
it('returns `mobile-issue-close` when `isEpicOpen` prop is false', () => {
vm.isEpicOpen = false;
expect(vm.statusIcon).toBe('mobile-issue-close');
});
});
......@@ -70,11 +74,13 @@ describe('epicHeader', () => {
describe('statusText', () => {
it('returns `Open` when `isEpicOpen` prop is true', () => {
vm.isEpicOpen = true;
expect(vm.statusText).toBe('Open');
});
it('returns `Closed` when `isEpicOpen` prop is false', () => {
vm.isEpicOpen = false;
expect(vm.statusText).toBe('Closed');
});
});
......@@ -82,11 +88,13 @@ describe('epicHeader', () => {
describe('actionButtonClass', () => {
it('returns classes `btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button` & `btn-close` when `isEpicOpen` prop is true', () => {
vm.isEpicOpen = true;
expect(vm.actionButtonClass).toContain('btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button btn-close');
});
it('returns classes `btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button` & `btn-open` when `isEpicOpen` prop is false', () => {
vm.isEpicOpen = false;
expect(vm.actionButtonClass).toContain('btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button btn-open');
});
});
......@@ -94,11 +102,13 @@ describe('epicHeader', () => {
describe('actionButtonText', () => {
it('returns `Close epic` when `isEpicOpen` prop is true', () => {
vm.isEpicOpen = true;
expect(vm.actionButtonText).toBe('Close epic');
});
it('returns `Reopen epic` when `isEpicOpen` prop is false', () => {
vm.isEpicOpen = false;
expect(vm.actionButtonText).toBe('Reopen epic');
});
});
......@@ -111,6 +121,7 @@ describe('epicHeader', () => {
vm.isEpicOpen = true;
vm.toggleStatus();
expect(vm.statusUpdating).toBe(true);
expect(vm.$emit).toHaveBeenCalledWith('toggleEpicStatus', stateEvent.close);
});
......@@ -120,6 +131,7 @@ describe('epicHeader', () => {
vm.isEpicOpen = false;
vm.toggleStatus();
expect(vm.statusUpdating).toBe(true);
expect(vm.$emit).toHaveBeenCalledWith('toggleEpicStatus', stateEvent.reopen);
});
......
......@@ -46,6 +46,7 @@ describe('newEpic', () => {
Vue.nextTick(() => {
vm.$el.querySelector('.dropdown-menu .btn-success').click();
expect(vm.service.createEpic).toHaveBeenCalled();
});
});
......@@ -73,6 +74,7 @@ describe('newEpic', () => {
expect(loadingIcon).toBeNull();
btnSave.click();
expect(loadingIcon).toBeDefined();
});
});
......
......@@ -98,6 +98,7 @@ describe('epicSidebar', () => {
const startDatePicker = vm.$el.querySelector('.block.start-date');
const endDatePicker = vm.$el.querySelector('.block.end-date');
expect(startDatePicker.querySelector('.value-type-fixed .value-content').innerText.trim()).toEqual('Jan 1, 2017');
expect(endDatePicker.querySelector('.value-type-fixed .value-content').innerText.trim()).toEqual('Jan 1, 2018');
});
......@@ -117,6 +118,7 @@ describe('epicSidebar', () => {
describe('isDateValid', () => {
it('returns true when fixed start and end dates are valid', () => {
const component = getComponent();
expect(component.isDateValid).toBe(true);
});
......@@ -125,6 +127,7 @@ describe('epicSidebar', () => {
initialStartDate: '2018-01-01',
initialEndDate: '2017-01-01',
});
expect(component.isDateValid).toBe(false);
});
......@@ -133,6 +136,7 @@ describe('epicSidebar', () => {
initialStartDateIsFixed: false,
initialEndDate: '2018-11-31',
});
expect(component.isDateValid).toBe(true);
});
......@@ -141,6 +145,7 @@ describe('epicSidebar', () => {
initialStartDateIsFixed: false,
initialDueDateIsFixed: false,
});
expect(component.isDateValid).toBe(true);
});
});
......@@ -181,10 +186,12 @@ describe('epicSidebar', () => {
it('should toggle contentContainer css class', () => {
const contentContainer = document.querySelector('.page-with-contextual-sidebar');
expect(contentContainer.classList.contains('right-sidebar-expanded')).toEqual(true);
expect(contentContainer.classList.contains('right-sidebar-collapsed')).toEqual(false);
vm.$el.querySelector('.gutter-toggle').click();
expect(contentContainer.classList.contains('right-sidebar-expanded')).toEqual(false);
expect(contentContainer.classList.contains('right-sidebar-collapsed')).toEqual(true);
});
......@@ -209,6 +216,7 @@ describe('epicSidebar', () => {
it('should save startDate', (done) => {
const date = '2017-01-01';
expect(component.store.startDate).toBeUndefined();
component.saveStartDate(date)
.then(() => {
......@@ -220,6 +228,7 @@ describe('epicSidebar', () => {
it('should save endDate', (done) => {
const date = '2017-01-01';
expect(component.store.endDate).toBeUndefined();
component.saveEndDate(date)
.then(() => {
......@@ -255,6 +264,7 @@ describe('epicSidebar', () => {
dateValue,
isFixed: true,
});
expect(component.store.startDateFixed).toBe(dateValue);
done();
}, 0);
......@@ -286,6 +296,7 @@ describe('epicSidebar', () => {
dateValue,
isFixed: true,
});
expect(component.store.dueDateFixed).toBe(dateValue);
done();
}, 0);
......@@ -303,6 +314,7 @@ describe('epicSidebar', () => {
it('initializes `epicContext.labels` as empty array when `label.isAny` is `true`', () => {
const labelIsAny = { isAny: true };
vm.handleLabelClick(labelIsAny);
expect(Array.isArray(vm.epicContext.labels)).toBe(true);
expect(vm.epicContext.labels.length).toBe(0);
});
......@@ -319,6 +331,7 @@ describe('epicSidebar', () => {
it('filters epicContext.labels to exclude provided `label` if it is already present in `epicContext.labels`', () => {
vm.handleLabelClick(label); // Select
vm.handleLabelClick(label); // Un-select
expect(vm.epicContext.labels.length).toBe(1);
expect(vm.epicContext.labels[0].id).toBe(labels[0].id);
});
......@@ -360,8 +373,10 @@ describe('epicSidebar', () => {
it('calls `addTodo` on service object when `todoExists` prop is `false`', () => {
spyOn(vm.service, 'addTodo').and.callThrough();
vm.store.setTodoExists(false);
expect(vm.savingTodoAction).toBe(false);
vm.handleToggleTodo();
expect(vm.savingTodoAction).toBe(true);
expect(vm.service.addTodo).toHaveBeenCalledWith(epicId);
});
......@@ -399,8 +414,10 @@ describe('epicSidebar', () => {
it('calls `deleteTodo` on service object when `todoExists` prop is `true`', () => {
spyOn(vm.service, 'deleteTodo').and.callThrough();
vm.store.setTodoExists(true);
expect(vm.savingTodoAction).toBe(false);
vm.handleToggleTodo();
expect(vm.savingTodoAction).toBe(true);
expect(vm.service.deleteTodo).toHaveBeenCalledWith(gl.TEST_HOST);
});
......@@ -456,6 +473,7 @@ describe('epicSidebar', () => {
it('should handle errors gracefully', (done) => {
const date = '2017-01-01';
expect(component.store.startDate).toBeUndefined();
component.saveDate('start', date)
.then(() => {
......
......@@ -104,6 +104,7 @@ describe('SidebarParticipants', () => {
it('returns popover config object containing `content` with href pointing to correct documentation', () => {
const hrefContent = vm.popoverOptions.content.trim();
expect(hrefContent).toContain(`${gon.gitlab_url}/help/user/group/epics/index.md#start-date-and-due-date`);
expect(hrefContent).toContain('More information');
});
......@@ -116,6 +117,7 @@ describe('SidebarParticipants', () => {
it('returns popover config object containing `content` with href pointing to correct documentation', () => {
const hrefContent = vm.dateInvalidPopoverOptions.content.trim();
expect(hrefContent).toContain(`${gon.gitlab_url}/help/user/group/epics/index.md#start-date-and-due-date`);
expect(hrefContent).toContain('How can I solve this?');
});
......@@ -152,6 +154,7 @@ describe('SidebarParticipants', () => {
it('sets `editing` prop to `false` and emits `toggleDateType` event on component', () => {
spyOn(vm, '$emit');
vm.stopEditing();
expect(vm.editing).toBe(false);
expect(vm.$emit).toHaveBeenCalledWith('toggleDateType', true, true);
});
......@@ -161,6 +164,7 @@ describe('SidebarParticipants', () => {
it('flips value of `editing` prop from `true` to `false` and vice-versa', () => {
vm.editing = true;
vm.toggleDatePicker();
expect(vm.editing).toBe(false);
});
});
......@@ -170,6 +174,7 @@ describe('SidebarParticipants', () => {
spyOn(vm, '$emit');
const date = new Date();
vm.newDateSelected(date);
expect(vm.editing).toBe(false);
expect(vm.$emit).toHaveBeenCalledWith('saveDate', date);
});
......@@ -179,6 +184,7 @@ describe('SidebarParticipants', () => {
it('emits `toggleDateType` event on component', () => {
spyOn(vm, '$emit');
vm.toggleDateType(true);
expect(vm.$emit).toHaveBeenCalledWith('toggleDateType', true);
});
});
......@@ -187,6 +193,7 @@ describe('SidebarParticipants', () => {
it('emits `toggleCollapse` event on component', () => {
spyOn(vm, '$emit');
vm.toggleSidebar();
expect(vm.$emit).toHaveBeenCalledWith('toggleCollapse');
});
});
......@@ -227,6 +234,7 @@ describe('SidebarParticipants', () => {
it('renders help icon', () => {
const helpIconEl = vm.$el.querySelector('.help-icon');
expect(helpIconEl).not.toBe(null);
expect(helpIconEl.getAttribute('tabindex')).toBe('0');
expect(helpIconEl.querySelector('use').getAttribute('xlink:href')).toContain('question-o');
......@@ -234,6 +242,7 @@ describe('SidebarParticipants', () => {
it('renderts edit button', () => {
const buttonEl = vm.$el.querySelector('button.btn-sidebar-action');
expect(buttonEl).not.toBe(null);
expect(buttonEl.innerText.trim()).toBe('Edit');
});
......@@ -245,6 +254,7 @@ describe('SidebarParticipants', () => {
it('renders fixed type date selection element', () => {
const valueFixedEl = vm.$el.querySelector('.value .value-type-fixed');
expect(valueFixedEl.querySelector('input[type="radio"]')).not.toBe(null);
expect(valueFixedEl.innerText.trim()).toContain('Fixed:');
expect(valueFixedEl.querySelector('.value-content').innerText.trim()).toContain('None');
......@@ -252,6 +262,7 @@ describe('SidebarParticipants', () => {
it('renders dynamic type date selection element', () => {
const valueDynamicEl = vm.$el.querySelector('.value abbr.value-type-dynamic');
expect(valueDynamicEl.querySelector('input[type="radio"]')).not.toBe(null);
expect(valueDynamicEl.innerText.trim()).toContain('From milestones:');
expect(valueDynamicEl.querySelector('.value-content').innerText.trim()).toContain('None');
......@@ -263,6 +274,7 @@ describe('SidebarParticipants', () => {
Vue.nextTick()
.then(() => {
const warningIconEl = vm.$el.querySelector('.date-warning-icon');
expect(warningIconEl).not.toBe(null);
expect(warningIconEl.getAttribute('tabindex')).toBe('0');
expect(warningIconEl.querySelector('use').getAttribute('xlink:href')).toContain('warning');
......
......@@ -28,6 +28,7 @@ describe('SidebarParticipants', () => {
it('emits `toggleCollapse` event on component', () => {
spyOn(vm, '$emit');
vm.onToggleSidebar();
expect(vm.$emit).toHaveBeenCalledWith('toggleCollapse');
});
});
......
......@@ -28,6 +28,7 @@ describe('SidebarSubscriptions', () => {
it('emits `toggleSubscription` event on component', () => {
spyOn(vm, '$emit');
vm.onToggleSubscription();
expect(vm.$emit).toHaveBeenCalledWith('toggleSubscription');
});
});
......@@ -36,6 +37,7 @@ describe('SidebarSubscriptions', () => {
it('emits `toggleCollapse` event on component', () => {
spyOn(vm, '$emit');
vm.onToggleSidebar();
expect(vm.$emit).toHaveBeenCalledWith('toggleCollapse');
});
});
......
......@@ -18,6 +18,7 @@ describe('Sidebar Service', () => {
spyOn(axios, 'put').and.stub();
const dateValue = '2018-06-21';
service.updateStartDate({ dateValue, isFixed: true });
expect(axios.put).toHaveBeenCalledWith(service.endpoint, {
start_date_is_fixed: true,
start_date_fixed: dateValue,
......@@ -30,6 +31,7 @@ describe('Sidebar Service', () => {
spyOn(axios, 'put').and.stub();
const dateValue = '2018-06-21';
service.updateEndDate({ dateValue, isFixed: true });
expect(axios.put).toHaveBeenCalledWith(service.endpoint, {
due_date_is_fixed: true,
due_date_fixed: dateValue,
......@@ -41,6 +43,7 @@ describe('Sidebar Service', () => {
it('returns axios instance with POST for `subscriptionEndpoint`', () => {
spyOn(axios, 'post').and.stub();
service.toggleSubscribed();
expect(axios.post).toHaveBeenCalled();
});
});
......@@ -50,6 +53,7 @@ describe('Sidebar Service', () => {
spyOn(axios, 'post').and.stub();
const epicId = 1;
service.addTodo(epicId);
expect(axios.post).toHaveBeenCalledWith(service.todoPath, {
issuable_id: epicId,
issuable_type: 'epic',
......@@ -61,6 +65,7 @@ describe('Sidebar Service', () => {
it('returns axios instance with DELETE for provided `todoDeletePath` param', () => {
spyOn(axios, 'delete').and.stub();
service.deleteTodo('/foo/bar');
expect(axios.delete).toHaveBeenCalledWith('/foo/bar');
});
});
......
......@@ -8,6 +8,7 @@ describe('Sidebar Store', () => {
const store = new SidebarStore({
startDate: dateString,
});
expect(store.startDate).toEqual(dateString);
});
......@@ -15,6 +16,7 @@ describe('Sidebar Store', () => {
const store = new SidebarStore({
endDate: dateString,
});
expect(store.endDate).toEqual(dateString);
});
});
......@@ -22,6 +24,7 @@ describe('Sidebar Store', () => {
describe('startDateTime', () => {
it('should return null when there is no startDate', () => {
const store = new SidebarStore({});
expect(store.startDateTime).toEqual(null);
});
......@@ -40,6 +43,7 @@ describe('Sidebar Store', () => {
describe('startDateTimeFixed', () => {
it('should return null when there is no startDateFixed', () => {
const store = new SidebarStore({});
expect(store.startDateTimeFixed).toEqual(null);
});
......@@ -58,6 +62,7 @@ describe('Sidebar Store', () => {
describe('endDateTime', () => {
it('should return null when there is no endDate', () => {
const store = new SidebarStore({});
expect(store.endDateTime).toEqual(null);
});
......@@ -76,6 +81,7 @@ describe('Sidebar Store', () => {
describe('dueDateTimeFixed', () => {
it('should return null when there is no dueDateFixed', () => {
const store = new SidebarStore({});
expect(store.dueDateTimeFixed).toEqual(null);
});
......@@ -96,6 +102,7 @@ describe('Sidebar Store', () => {
const store = new SidebarStore({ subscribed: true });
store.setSubscribed(false);
expect(store.subscribed).toEqual(false);
});
});
......@@ -105,6 +112,7 @@ describe('Sidebar Store', () => {
const store = new SidebarStore({ todoExists: true });
store.setTodoExists(false);
expect(store.todoExists).toEqual(false);
});
});
......@@ -114,6 +122,7 @@ describe('Sidebar Store', () => {
const store = new SidebarStore({ todoDeletePath: gl.TEST_HOST });
store.setTodoDeletePath('/foo/bar');
expect(store.todoDeletePath).toEqual('/foo/bar');
});
});
......
......@@ -30,6 +30,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
it('should return weightTokenKey as part of tokenKeys', () => {
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
expect(match).toEqual(weightTokenKey);
});
......@@ -41,6 +42,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
it('should return assignee as an array', () => {
const assignee = tokenKeys.find(tokenKey => tokenKey.key === 'assignee');
expect(assignee.type).toEqual('array');
});
});
......@@ -73,6 +75,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
it('should return weightConditions as part of conditions', () => {
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
expect(weightConditions.length).toBe(2);
});
});
......@@ -80,12 +83,14 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
describe('searchByKey', () => {
it('should return null when key not found', () => {
const tokenKey = IssuesFilteredSearchTokenKeysEE.searchByKey('notakey');
expect(tokenKey).toBeNull();
});
it('should return tokenKey when found by key', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const result = IssuesFilteredSearchTokenKeysEE.searchByKey(tokenKeys[0].key);
expect(result).toEqual(tokenKeys[0]);
});
......@@ -93,6 +98,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = IssuesFilteredSearchTokenKeysEE.searchByKey(weightTokenKey.key);
expect(result).toEqual(match);
});
});
......@@ -100,12 +106,14 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
describe('searchBySymbol', () => {
it('should return null when symbol not found', () => {
const tokenKey = IssuesFilteredSearchTokenKeysEE.searchBySymbol('notasymbol');
expect(tokenKey).toBeNull();
});
it('should return tokenKey when found by symbol', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const result = IssuesFilteredSearchTokenKeysEE.searchBySymbol(tokenKeys[0].symbol);
expect(result).toEqual(tokenKeys[0]);
});
......@@ -113,6 +121,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = IssuesFilteredSearchTokenKeysEE.searchBySymbol(weightTokenKey.symbol);
expect(result).toEqual(match);
});
});
......@@ -120,6 +129,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
describe('searchByKeyParam', () => {
it('should return null when key param not found', () => {
const tokenKey = IssuesFilteredSearchTokenKeysEE.searchByKeyParam('notakeyparam');
expect(tokenKey).toBeNull();
});
......@@ -127,6 +137,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const result = IssuesFilteredSearchTokenKeysEE
.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
......@@ -134,6 +145,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.getAlternatives();
const result = IssuesFilteredSearchTokenKeysEE
.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
......@@ -141,6 +153,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const tokenKeys = IssuesFilteredSearchTokenKeysEE.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = IssuesFilteredSearchTokenKeysEE.searchByKeyParam(weightTokenKey.key);
expect(result).toEqual(match);
});
});
......@@ -148,6 +161,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
describe('searchByConditionUrl', () => {
it('should return null when condition url not found', () => {
const condition = IssuesFilteredSearchTokenKeysEE.searchByConditionUrl(null);
expect(condition).toBeNull();
});
......@@ -155,6 +169,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const conditions = IssuesFilteredSearchTokenKeysEE.getConditions();
const result = IssuesFilteredSearchTokenKeysEE
.searchByConditionUrl(conditions[0].url);
expect(result).toBe(conditions[0]);
});
......@@ -163,6 +178,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
const result = IssuesFilteredSearchTokenKeysEE
.searchByConditionUrl(weightConditions[0].url);
expect(result).toBe(weightConditions[0]);
});
});
......@@ -171,6 +187,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
it('should return null when condition tokenKey and value not found', () => {
const condition = IssuesFilteredSearchTokenKeysEE
.searchByConditionKeyValue(null, null);
expect(condition).toBeNull();
});
......@@ -178,6 +195,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const conditions = IssuesFilteredSearchTokenKeysEE.getConditions();
const result = IssuesFilteredSearchTokenKeysEE
.searchByConditionKeyValue(conditions[0].tokenKey, conditions[0].value);
expect(result).toEqual(conditions[0]);
});
......@@ -186,6 +204,7 @@ describe('Filtered Search Token Keys (Issues EE)', () => {
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
const result = IssuesFilteredSearchTokenKeysEE
.searchByConditionKeyValue(weightConditions[0].tokenKey, weightConditions[0].value);
expect(result).toEqual(weightConditions[0]);
});
});
......
......@@ -80,6 +80,7 @@ describe('AppComponent', () => {
nodeActionActive: false,
};
vm.setNodeActionStatus(node, true);
expect(node.nodeActionActive).toBe(true);
});
});
......@@ -87,6 +88,7 @@ describe('AppComponent', () => {
describe('initNodeDetailsPolling', () => {
it('initializes SmartInterval and sets it to component', () => {
vm.initNodeDetailsPolling(2);
expect(vm.nodePollingInterval).toBeDefined();
});
});
......@@ -148,6 +150,7 @@ describe('AppComponent', () => {
.then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith('nodeDetailsLoaded', jasmine.any(Object));
const nodeDetails = vm.store.state.nodeDetails['1'];
expect(nodeDetails).toBeDefined();
expect(nodeDetails.syncStatusUnavailable).toBe(true);
expect(nodeDetails.health).toBe('Request failed with status code 404');
......@@ -166,6 +169,7 @@ describe('AppComponent', () => {
.then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith('nodeDetailsLoaded', jasmine.any(Object));
const nodeDetails = vm.store.state.nodeDetails['1'];
expect(nodeDetails).toBeDefined();
expect(nodeDetails.syncStatusUnavailable).toBe(true);
expect(nodeDetails.health).toBe('Network Error');
......@@ -184,6 +188,7 @@ describe('AppComponent', () => {
.then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith('nodeDetailsLoaded', jasmine.any(Object));
const nodeDetails = vm.store.state.nodeDetails['1'];
expect(nodeDetails).toBeDefined();
expect(nodeDetails.syncStatusUnavailable).toBe(true);
expect(nodeDetails.health).toBe('timeout of 0ms exceeded');
......@@ -209,6 +214,7 @@ describe('AppComponent', () => {
expect(document.querySelector('.flash-text').innerText.trim()).toBe(
'Node Authentication was successfully repaired.',
);
expect(node.nodeActionActive).toBe(false);
})
.then(done)
......@@ -230,6 +236,7 @@ describe('AppComponent', () => {
expect(document.querySelector('.flash-text').innerText.trim()).toBe(
'Something went wrong while repairing node',
);
expect(node.nodeActionActive).toBe(false);
})
.then(done)
......@@ -279,6 +286,7 @@ describe('AppComponent', () => {
expect(document.querySelector('.flash-text').innerText.trim()).toBe(
'Something went wrong while changing node status',
);
expect(node.nodeActionActive).toBe(false);
})
.then(done)
......@@ -340,6 +348,7 @@ describe('AppComponent', () => {
spyOn(vm, 'toggleNode').and.stub();
vm.handleNodeAction();
expect(vm.showModal).toBe(false);
expect(vm.toggleNode).toHaveBeenCalledWith(vm.targetNode);
});
......@@ -351,6 +360,7 @@ describe('AppComponent', () => {
spyOn(vm, 'removeNode').and.stub();
vm.handleNodeAction();
expect(vm.showModal).toBe(false);
expect(vm.removeNode).toHaveBeenCalledWith(vm.targetNode);
});
......@@ -377,6 +387,7 @@ describe('AppComponent', () => {
modalMessage,
modalActionLabel,
});
expect(vm.targetNode).toBe(node);
expect(vm.targetNodeActionType).toBe(NODE_ACTIONS.TOGGLE);
expect(vm.modalKind).toBe(modalKind);
......@@ -393,6 +404,7 @@ describe('AppComponent', () => {
modalMessage,
modalActionLabel,
});
expect(vm.showModal).toBe(true);
});
......@@ -407,6 +419,7 @@ describe('AppComponent', () => {
modalMessage,
modalActionLabel,
});
expect(vm.toggleNode).toHaveBeenCalledWith(vm.targetNode);
});
......@@ -419,6 +432,7 @@ describe('AppComponent', () => {
modalMessage,
modalActionLabel,
});
expect(vm.showModal).toBe(true);
});
});
......@@ -427,6 +441,7 @@ describe('AppComponent', () => {
it('sets `showModal` to `false`', () => {
vm.showModal = true;
vm.hideNodeActionModal();
expect(vm.showModal).toBe(false);
});
});
......@@ -436,6 +451,7 @@ describe('AppComponent', () => {
it('binds event handler for `pollNodeDetails`', () => {
spyOn(eventHub, '$on');
const vmX = createComponent();
expect(eventHub.$on).toHaveBeenCalledWith('pollNodeDetails', jasmine.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('showNodeActionModal', jasmine.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('repairNode', jasmine.any(Function));
......@@ -448,6 +464,7 @@ describe('AppComponent', () => {
spyOn(eventHub, '$off');
const vmX = createComponent();
vmX.$destroy();
expect(eventHub.$off).toHaveBeenCalledWith('pollNodeDetails', jasmine.any(Function));
expect(eventHub.$off).toHaveBeenCalledWith('showNodeActionModal', jasmine.any(Function));
expect(eventHub.$off).toHaveBeenCalledWith('repairNode', jasmine.any(Function));
......@@ -461,6 +478,7 @@ describe('AppComponent', () => {
it('renders loading animation when `isLoading` is true', () => {
vm.isLoading = true;
expect(
vm.$el.querySelectorAll('.loading-animation.prepend-top-20.append-bottom-20').length,
).not.toBe(0);
......
......@@ -33,10 +33,12 @@ describe('GeoNodeActionsComponent', () => {
describe('isToggleAllowed', () => {
it('returns boolean value representing if toggle on node can be allowed', () => {
let vmX = createComponent(mockNodes[0], true, false);
expect(vmX.isToggleAllowed).toBeFalsy();
vmX.$destroy();
vmX = createComponent(mockNodes[1]);
expect(vmX.isToggleAllowed).toBeTruthy();
vmX.$destroy();
});
......@@ -46,11 +48,13 @@ describe('GeoNodeActionsComponent', () => {
it('returns label for toggle button for a node', () => {
let mockNode = Object.assign({}, mockNodes[1]);
let vmX = createComponent(mockNode);
expect(vmX.nodeToggleLabel).toBe('Disable');
vmX.$destroy();
mockNode = Object.assign({}, mockNodes[1], { enabled: false });
vmX = createComponent(mockNode);
expect(vmX.nodeToggleLabel).toBe('Enable');
vmX.$destroy();
});
......@@ -62,6 +66,7 @@ describe('GeoNodeActionsComponent', () => {
it('emits showNodeActionModal with actionType `toggle`, node reference, modalMessage and modalActionLabel', () => {
spyOn(eventHub, '$emit');
vm.onToggleNode();
expect(eventHub.$emit).toHaveBeenCalledWith('showNodeActionModal', {
actionType: NODE_ACTIONS.TOGGLE,
node: vm.node,
......@@ -75,6 +80,7 @@ describe('GeoNodeActionsComponent', () => {
it('emits showNodeActionModal with actionType `remove`, node reference, modalKind, modalMessage and modalActionLabel', () => {
spyOn(eventHub, '$emit');
vm.onRemoveNode();
expect(eventHub.$emit).toHaveBeenCalledWith('showNodeActionModal', {
actionType: NODE_ACTIONS.REMOVE,
node: vm.node,
......@@ -89,6 +95,7 @@ describe('GeoNodeActionsComponent', () => {
it('emits `repairNode` event with node reference', () => {
spyOn(eventHub, '$emit');
vm.onRepairNode();
expect(eventHub.$emit).toHaveBeenCalledWith('repairNode', vm.node);
});
});
......
......@@ -24,6 +24,7 @@ describe('GeoNodeDetailItemComponent', () => {
describe('template', () => {
it('renders container elements correctly', () => {
const vm = createComponent();
expect(vm.$el.classList.contains('node-detail-item')).toBeTruthy();
expect(vm.$el.querySelectorAll('.node-detail-title').length).not.toBe(0);
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('GitLab version');
......@@ -32,6 +33,7 @@ describe('GeoNodeDetailItemComponent', () => {
it('renders plain item value', () => {
const vm = createComponent();
expect(vm.$el.querySelectorAll('.node-detail-value').length).not.toBe(0);
expect(vm.$el.querySelector('.node-detail-value').innerText.trim()).toBe('10.4.0-pre');
vm.$destroy();
......@@ -52,6 +54,7 @@ describe('GeoNodeDetailItemComponent', () => {
itemValueType: VALUE_TYPE.GRAPH,
itemValue: { successCount: 5, failureCount: 3, totalCount: 10 },
});
expect(vm.$el.querySelectorAll('.stacked-progress-bar').length).not.toBe(0);
vm.$destroy();
});
......@@ -66,6 +69,7 @@ describe('GeoNodeDetailItemComponent', () => {
});
const iconEl = vm.$el.querySelector('.detail-value-stale-icon');
expect(iconEl).not.toBeNull();
expect(iconEl.dataset.originalTitle).toBe(itemValueStaleTooltip);
expect(iconEl.querySelector('use').getAttribute('xlink:href')).toContain('time-out');
......@@ -88,6 +92,7 @@ describe('GeoNodeDetailItemComponent', () => {
},
},
});
expect(vm.$el.querySelectorAll('.node-sync-settings').length).not.toBe(0);
vm.$destroy();
});
......@@ -101,6 +106,7 @@ describe('GeoNodeDetailItemComponent', () => {
eventTimeStamp: rawMockNodeDetails.last_event_timestamp,
},
});
expect(vm.$el.querySelectorAll('.event-status-timestamp').length).not.toBe(0);
vm.$destroy();
});
......
......@@ -47,6 +47,7 @@ describe('GeoNodeDetailsComponent', () => {
healthy: false,
});
const vmX = createComponent({ nodeDetails });
expect(vmX.errorMessage).toBe('Something went wrong.');
expect(vmX.hasError).toBeTruthy();
vmX.$destroy();
......@@ -64,6 +65,7 @@ describe('GeoNodeDetailsComponent', () => {
primaryRevision: 'b93c51850b',
});
const vmX = createComponent({ nodeDetails });
expect(vmX.errorMessage).toBe('GitLab version does not match the primary node version');
expect(vmX.hasVersionMismatch).toBeTruthy();
vmX.$destroy();
......
......@@ -45,6 +45,7 @@ describe('GeoNodeEventStatus', () => {
describe('eventString', () => {
it('returns computed event string when `eventTypeLogStatus` prop is true', () => {
const vmWithLogStatus = createComponent({ eventTypeLogStatus: true });
expect(vmWithLogStatus.eventString).toBe(mockNodeDetails.lastEvent.id);
vmWithLogStatus.$destroy();
});
......@@ -68,6 +69,7 @@ describe('GeoNodeEventStatus', () => {
eventId: 0,
eventTimeStamp: 0,
});
expect(vmWithoutTimestamp.$el.querySelectorAll('strong').length).not.toBe(0);
expect(vmWithoutTimestamp.$el.querySelectorAll('.event-status-timestamp').length).toBe(0);
expect(vmWithoutTimestamp.$el.querySelector('strong').innerText.trim()).toBe('Not available');
......
......@@ -17,6 +17,7 @@ describe('GeoNodeHealthStatusComponent', () => {
describe('healthCssClass', () => {
it('returns CSS class representing `status` prop value', () => {
const vm = createComponent('Healthy');
expect(vm.healthCssClass).toBe('geo-node-healthy');
vm.$destroy();
});
......@@ -25,22 +26,27 @@ describe('GeoNodeHealthStatusComponent', () => {
describe('statusIconName', () => {
it('returns icon name representing `status` prop value', () => {
let vm = createComponent('Healthy');
expect(vm.statusIconName).toBe('status_success');
vm.$destroy();
vm = createComponent('Unhealthy');
expect(vm.statusIconName).toBe('status_failed');
vm.$destroy();
vm = createComponent('Disabled');
expect(vm.statusIconName).toBe('status_canceled');
vm.$destroy();
vm = createComponent('Unknown');
expect(vm.statusIconName).toBe('status_warning');
vm.$destroy();
vm = createComponent('Offline');
expect(vm.statusIconName).toBe('status_canceled');
vm.$destroy();
});
......@@ -50,10 +56,12 @@ describe('GeoNodeHealthStatusComponent', () => {
describe('template', () => {
it('renders container elements correctly', () => {
const vm = createComponent('Healthy');
expect(vm.$el.classList.contains('detail-section-item')).toBe(true);
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('Health status');
const iconContainerEl = vm.$el.querySelector('.node-detail-value.node-health-status');
expect(iconContainerEl).not.toBeNull();
expect(iconContainerEl.querySelector('svg use').getAttribute('xlink:href')).toContain('#status_success');
expect(iconContainerEl.querySelector('.status-text').innerText.trim()).toBe('Healthy');
......
......@@ -56,18 +56,21 @@ describe('GeoNodeItemComponent', () => {
describe('showNodeDetails', () => {
it('returns `false` if Node details are still loading', () => {
vm.isNodeDetailsLoading = true;
expect(vm.showNodeDetails).toBeFalsy();
});
it('returns `false` if Node details failed to load', () => {
vm.isNodeDetailsLoading = false;
vm.isNodeDetailsFailed = true;
expect(vm.showNodeDetails).toBeFalsy();
});
it('returns `true` if Node details loaded', () => {
vm.isNodeDetailsLoading = false;
vm.isNodeDetailsFailed = false;
expect(vm.showNodeDetails).toBeTruthy();
});
});
......@@ -84,6 +87,7 @@ describe('GeoNodeItemComponent', () => {
const vmNodePrimary = createComponent(mockNodeSecondary);
vmNodePrimary.handleNodeDetails(mockNodeDetails);
expect(vmNodePrimary.isNodeDetailsLoading).toBeFalsy();
expect(vmNodePrimary.isNodeDetailsFailed).toBeFalsy();
expect(vmNodePrimary.errorMessage).toBe('');
......@@ -93,6 +97,7 @@ describe('GeoNodeItemComponent', () => {
// With default mock data without matching ID
vm.handleNodeDetails(mockNodeDetails);
expect(vm.isNodeDetailsLoading).toBeTruthy();
expect(vm.nodeDetails).not.toBe(mockNodeDetails);
expect(vm.nodeHealthStatus).not.toBe(mockNodeDetails.health);
......@@ -104,6 +109,7 @@ describe('GeoNodeItemComponent', () => {
spyOn(eventHub, '$emit');
vm.handleMounted();
expect(eventHub.$emit).toHaveBeenCalledWith('pollNodeDetails', vm.node);
});
});
......@@ -114,6 +120,7 @@ describe('GeoNodeItemComponent', () => {
spyOn(eventHub, '$on');
const vmX = createComponent();
expect(eventHub.$on).toHaveBeenCalledWith('nodeDetailsLoaded', jasmine.any(Function));
vmX.$destroy();
});
......@@ -125,6 +132,7 @@ describe('GeoNodeItemComponent', () => {
const vmX = createComponent();
vmX.$destroy();
expect(eventHub.$off).toHaveBeenCalledWith('nodeDetailsLoaded', jasmine.any(Function));
});
});
......
......@@ -24,6 +24,7 @@ describe('GeoNodeSyncSettingsComponent', () => {
describe('syncType', () => {
it('returns string representing sync type', () => {
const vm = createComponent();
expect(vm.syncType).toBe('Selective (namespaces)');
vm.$destroy();
});
......@@ -38,12 +39,14 @@ describe('GeoNodeSyncSettingsComponent', () => {
id: 0,
timeStamp: 0,
});
expect(vmEmptyTimestamp.eventTimestampEmpty).toBeTruthy();
vmEmptyTimestamp.$destroy();
});
it('return `false` if one of the event timestamp is present', () => {
const vm = createComponent();
expect(vm.eventTimestampEmpty).toBeFalsy();
vm.$destroy();
});
......@@ -93,6 +96,7 @@ describe('GeoNodeSyncSettingsComponent', () => {
describe('template', () => {
it('renders `Unknown` when `syncStatusUnavailable` prop is true', () => {
const vmSyncUnavailable = createComponent(true);
expect(vmSyncUnavailable.$el.innerText.trim()).toBe('Unknown');
vmSyncUnavailable.$destroy();
});
......
......@@ -18,6 +18,7 @@ describe('GeoNodesListComponent', () => {
describe('template', () => {
it('renders container element correctly', () => {
const vm = createComponent();
expect(vm.$el.classList.contains('card')).toBe(true);
vm.$destroy();
});
......
......@@ -40,6 +40,7 @@ describe('NodeDetailsSectionSync', () => {
Vue.nextTick()
.then(() => {
const syncSettings = vm.syncSettings();
expect(syncSettings.syncStatusUnavailable).toBe(true);
expect(syncSettings.namespaces).toBe(mockNodeDetails.namespaces);
expect(syncSettings.lastEvent).toBe(mockNodeDetails.lastEvent);
......
......@@ -31,11 +31,13 @@ describe('SectionRevealButton', () => {
describe('computed', () => {
it('return `angle-up` when toggleState prop is true', () => {
vm.toggleState = true;
expect(vm.toggleButtonIcon).toBe('angle-up');
});
it('return `angle-down` when toggleState prop is false', () => {
vm.toggleState = false;
expect(vm.toggleButtonIcon).toBe('angle-down');
});
});
......@@ -45,12 +47,14 @@ describe('SectionRevealButton', () => {
it('updates `toggleState` prop to toggle from previous value', () => {
vm.toggleState = true;
vm.onClickButton();
expect(vm.toggleState).toBe(false);
});
it('emits `toggleButton` event on component', () => {
spyOn(vm, '$emit');
vm.onClickButton();
expect(vm.$emit).toHaveBeenCalledWith('toggleButton', vm.toggleState);
});
});
......
......@@ -14,6 +14,7 @@ describe('GeoNodesService', () => {
it('returns axios instance for Geo nodes path', () => {
spyOn(axios, 'get').and.stub();
service.getGeoNodes();
expect(axios.get).toHaveBeenCalledWith(service.geoNodesPath);
});
});
......@@ -22,6 +23,7 @@ describe('GeoNodesService', () => {
it('returns axios instance for Geo node details path', () => {
spyOn(axios, 'get').and.stub();
service.getGeoNodeDetails(2);
expect(axios.get).toHaveBeenCalled();
});
});
......
......@@ -22,6 +22,7 @@ describe('GeoNodesStore', () => {
describe('setNodes', () => {
it('sets nodes list to state', () => {
store.setNodes(mockNodes);
expect(store.getNodes().length).toBe(mockNodes.length);
});
});
......@@ -29,6 +30,7 @@ describe('GeoNodesStore', () => {
describe('setNodeDetails', () => {
it('sets node details to state', () => {
store.setNodeDetails(2, rawMockNodeDetails);
expect(typeof store.getNodeDetails(2)).toBe('object');
});
});
......@@ -47,6 +49,7 @@ describe('GeoNodesStore', () => {
describe('formatNode', () => {
it('returns formatted raw node object', () => {
const node = GeoNodesStore.formatNode(mockNodes[0]);
expect(node.id).toBe(mockNodes[0].id);
expect(node.url).toBe(mockNodes[0].url);
expect(node.basePath).toBe(mockNodes[0]._links.self);
......@@ -58,6 +61,7 @@ describe('GeoNodesStore', () => {
describe('formatNodeDetails', () => {
it('returns formatted raw node details object', () => {
const nodeDetails = GeoNodesStore.formatNodeDetails(rawMockNodeDetails);
expect(nodeDetails.healthStatus).toBe(rawMockNodeDetails.health_status);
expect(nodeDetails.replicationSlotWAL)
.toBe(rawMockNodeDetails.replication_slots_max_retained_wal_bytes);
......
......@@ -53,6 +53,7 @@ describe('AppComponent', () => {
spyOn(vm.store, 'setMembers');
vm.fetchContributedMembers();
expect(vm.isLoading).toBe(true);
setTimeout(() => {
expect(vm.isLoading).toBe(false);
......@@ -66,6 +67,7 @@ describe('AppComponent', () => {
mock.onGet(vm.service.memberContributionsPath).reply(500, {});
vm.fetchContributedMembers();
expect(vm.isLoading).toBe(true);
setTimeout(() => {
expect(vm.isLoading).toBe(false);
......@@ -83,6 +85,7 @@ describe('AppComponent', () => {
const columnName = 'fullname';
vm.handleColumnClick(columnName);
expect(vm.store.sortMembers).toHaveBeenCalledWith(columnName);
});
});
......@@ -103,6 +106,7 @@ describe('AppComponent', () => {
.$nextTick()
.then(() => {
const loadingEl = vm.$el.querySelector('.loading-animation');
expect(loadingEl).not.toBeNull();
expect(loadingEl.querySelector('i').getAttribute('aria-label')).toBe(
'Loading contribution stats for group members',
......
......@@ -31,12 +31,14 @@ describe('TableBodyComponent', () => {
describe('template', () => {
it('renders row item element', () => {
const rowEl = vm.$el.querySelector('tr');
expect(rowEl).not.toBeNull();
expect(rowEl.querySelectorAll('td').length).toBe(7);
});
it('renders username row cell element', () => {
const cellEl = vm.$el.querySelector('td strong');
expect(cellEl).not.toBeNull();
expect(cellEl.querySelector('a').getAttribute('href')).toBe(rawMembers[0].user_web_url);
});
......
......@@ -39,12 +39,14 @@ describe('TableHeaderComponent', () => {
describe('getColumnIconMeta', () => {
it('returns `angle-up` and `Ascending` for sortIcon and iconTooltip respectively when provided columnName in sortOrders has value greater than 0', () => {
const iconMeta = vm.getColumnIconMeta(columnName, { fullname: 1 });
expect(iconMeta.sortIcon).toBe('angle-up');
expect(iconMeta.iconTooltip).toBe('Ascending');
});
it('returns `angle-down` and `Descending` for sortIcon and iconTooltip respectively when provided columnName in sortOrders has value less than 0', () => {
const iconMeta = vm.getColumnIconMeta(columnName, { fullname: -1 });
expect(iconMeta.sortIcon).toBe('angle-down');
expect(iconMeta.iconTooltip).toBe('Descending');
});
......@@ -66,12 +68,14 @@ describe('TableHeaderComponent', () => {
it('emits `onColumnClick` event with columnName param on component instance', () => {
spyOn(vm, '$emit');
vm.onColumnClick(columnName);
expect(vm.$emit).toHaveBeenCalledWith('onColumnClick', columnName);
});
it('updates columnIconMeta prop for provided columnName', () => {
spyOn(vm, 'getColumnIconMeta');
vm.onColumnClick(columnName);
expect(vm.getColumnIconMeta).toHaveBeenCalledWith(columnName, vm.sortOrders);
});
});
......@@ -80,6 +84,7 @@ describe('TableHeaderComponent', () => {
describe('template', () => {
it('renders table column header with sort order icon', () => {
const headerItemEl = vm.$el.querySelector('tr th');
expect(headerItemEl).not.toBeNull();
expect(headerItemEl.innerText.trim()).toBe('Name');
expect(headerItemEl.querySelector('svg use').getAttribute('xlink:href')).toContain(
......
......@@ -21,6 +21,7 @@ describe('GroupMemberService', () => {
it('returns axios instance for memberContributionsPath', () => {
spyOn(axios, 'get').and.stub();
service.getContributedMembers();
expect(axios.get).toHaveBeenCalledWith(service.memberContributionsPath);
});
});
......
......@@ -29,6 +29,7 @@ describe('GroupMemberStore', () => {
describe('setMembers', () => {
it('sets members to store state', () => {
store.setMembers(rawMembers);
expect(store.state.members.length).toBe(rawMembers.length);
});
});
......@@ -39,10 +40,12 @@ describe('GroupMemberStore', () => {
store.setMembers(rawMembers);
let [firstMember] = store.state.members;
expect(firstMember.fullname).toBe('Administrator');
store.sortMembers('fullname');
([firstMember] = store.state.members);
expect(firstMember.fullname).toBe('Terrell Graham');
});
});
......
......@@ -139,6 +139,7 @@ describe('IssueToken', () => {
it('shows reference, title, and state', () => {
const stateIcon = vm.$refs.reference.querySelector('svg');
expect(stateIcon.getAttribute('aria-label')).toEqual(state);
expect(vm.$refs.reference.textContent.trim()).toEqual(displayReference);
expect(vm.$refs.title.textContent.trim()).toEqual(title);
......@@ -199,6 +200,7 @@ describe('IssueToken', () => {
it('when getting checked', () => {
expect(removeRequestSpy).not.toHaveBeenCalled();
vm.onRemoveRequest();
expect(removeRequestSpy).toHaveBeenCalled();
});
});
......
......@@ -124,24 +124,28 @@ describe('RelatedIssuesBlock', () => {
it('reorder item correctly when an item is moved to the top', () => {
const beforeAfterIds = vm.getBeforeAfterId(vm.$el.querySelector('ul li:first-child'));
expect(beforeAfterIds.beforeId).toBeNull();
expect(beforeAfterIds.afterId).toBe(2);
});
it('reorder item correctly when an item is moved to the bottom', () => {
const beforeAfterIds = vm.getBeforeAfterId(vm.$el.querySelector('ul li:last-child'));
expect(beforeAfterIds.beforeId).toBe(4);
expect(beforeAfterIds.afterId).toBeNull();
});
it('reorder item correctly when an item is swapped with adjecent item', () => {
const beforeAfterIds = vm.getBeforeAfterId(vm.$el.querySelector('ul li:nth-child(3)'));
expect(beforeAfterIds.beforeId).toBe(2);
expect(beforeAfterIds.afterId).toBe(4);
});
it('reorder item correctly when an item is moved somewhere in the middle', () => {
const beforeAfterIds = vm.getBeforeAfterId(vm.$el.querySelector('ul li:nth-child(4)'));
expect(beforeAfterIds.beforeId).toBe(3);
expect(beforeAfterIds.afterId).toBe(5);
});
......@@ -149,6 +153,7 @@ describe('RelatedIssuesBlock', () => {
it('when expanding add related issue form', () => {
expect(toggleAddRelatedIssuesFormSpy).not.toHaveBeenCalled();
vm.toggleAddRelatedIssuesForm();
expect(toggleAddRelatedIssuesFormSpy).toHaveBeenCalled();
});
});
......
......@@ -49,6 +49,7 @@ describe('RelatedIssuesStore', () => {
expect(store.state.relatedIssues[3].id).toBe(issuable4.id);
store.updateIssueOrder(3, 0);
expect(store.state.relatedIssues[0].id).toBe(issuable4.id);
});
});
......
......@@ -108,6 +108,7 @@ describe('Kubernetes Logs', () => {
it('escapes the pod name', () => {
kubernetesLog = new KubernetesLogs(kubernetesLogContainer);
expect(kubernetesLog.podName).toContain('"><img src=x onerror=alert(document.domain)> production');
});
});
......
......@@ -19,6 +19,7 @@ describe('AddLicenseFormDropdown', () => {
$(vm.$el)
.val('LGPL')
.trigger('change');
expect(vm.$emit).toHaveBeenCalledWith('input', 'LGPL');
});
......@@ -45,6 +46,7 @@ describe('AddLicenseFormDropdown', () => {
element.on('select2-open', () => {
const options = $('.select2-drop .select2-result');
expect(KNOWN_LICENSES.length).toEqual(options.length);
options.each(function() {
expect(KNOWN_LICENSES).toContain($(this).text());
......
......@@ -30,6 +30,7 @@ describe('AddLicenseForm', () => {
newStatus: LICENSE_APPROVAL_STATUS.APPROVED,
license: { name },
});
expect(vm.$emit).toHaveBeenCalledWith('closeForm');
done();
});
......@@ -49,12 +50,14 @@ describe('AddLicenseForm', () => {
it('is true if the approvalStatus is empty', () => {
vm.licenseName = 'FOO';
vm.approvalStatus = '';
expect(vm.submitDisabled).toBe(true);
});
it('is true if the licenseName is empty', () => {
vm.licenseName = '';
vm.approvalStatus = LICENSE_APPROVAL_STATUS.APPROVED;
expect(vm.submitDisabled).toBe(true);
});
......@@ -62,6 +65,7 @@ describe('AddLicenseForm', () => {
vm = mountComponent(Component, { managedLicenses: [{ name: 'FOO' }] });
vm.licenseName = 'FOO';
vm.approvalStatus = LICENSE_APPROVAL_STATUS.APPROVED;
expect(vm.submitDisabled).toBe(true);
});
});
......@@ -70,12 +74,14 @@ describe('AddLicenseForm', () => {
it('is true if the entered license is duplicated', () => {
vm = mountComponent(Component, { managedLicenses: [{ name: 'FOO' }] });
vm.licenseName = 'FOO';
expect(vm.isInvalidLicense).toBe(true);
});
it('is false if the entered license is unique', () => {
vm = mountComponent(Component, { managedLicenses: [{ name: 'FOO' }] });
vm.licenseName = 'FOO2';
expect(vm.isInvalidLicense).toBe(false);
});
});
......@@ -84,11 +90,13 @@ describe('AddLicenseForm', () => {
describe('template', () => {
it('renders the license select dropdown', () => {
const dropdownElement = vm.$el.querySelector('#js-license-dropdown');
expect(dropdownElement).not.toBeNull();
});
it('renders the license approval radio buttons dropdown', () => {
const radioButtonParents = vm.$el.querySelectorAll('.form-check');
expect(radioButtonParents.length).toBe(2);
expect(radioButtonParents[0].innerText.trim()).toBe('Approve');
expect(radioButtonParents[0].querySelector('.form-check-input')).not.toBeNull();
......@@ -101,6 +109,7 @@ describe('AddLicenseForm', () => {
vm.licenseName = 'FOO';
Vue.nextTick(() => {
const feedbackElement = vm.$el.querySelector('.invalid-feedback');
expect(feedbackElement).not.toBeNull();
expect(feedbackElement.classList).toContain('d-block');
expect(feedbackElement.innerText.trim()).toBe(
......@@ -116,6 +125,7 @@ describe('AddLicenseForm', () => {
expect(vm.submitDisabled).toBe(true);
const submitButton = vm.$el.querySelector('.js-submit');
expect(submitButton).not.toBeNull();
expect(submitButton.disabled).toBe(true);
done();
......
......@@ -72,12 +72,14 @@ describe('DeleteConfirmationModal', () => {
it('by clicking the cancel button', () => {
const linkEl = vm.$el.querySelector('.js-modal-cancel-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
it('by clicking the X button', () => {
const linkEl = vm.$el.querySelector('.js-modal-close-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
});
......@@ -86,6 +88,7 @@ describe('DeleteConfirmationModal', () => {
it('by clicking the confirmation button', () => {
const linkEl = vm.$el.querySelector('.js-modal-primary-action');
linkEl.click();
expect(actions.deleteLicense).toHaveBeenCalledWith(
jasmine.any(Object),
store.state.currentLicenseInModal,
......@@ -98,18 +101,21 @@ describe('DeleteConfirmationModal', () => {
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('Remove license?');
});
it('renders button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Remove license');
});
it('renders modal body', () => {
const modalBody = vm.$el.querySelector('.modal-body');
expect(modalBody).not.toBeNull();
expect(trimText(modalBody.innerText)).toBe(
`You are about to remove the license, ${approvedLicense.name}, from this project.`,
......
......@@ -40,12 +40,14 @@ describe('LicenseIssueBody', () => {
it('renders button to open modal', () => {
const linkEl = vm.$el.querySelector('.license-item > .btn-link');
expect(linkEl).not.toBeNull();
expect(linkEl.innerText.trim()).toBe(issue.name);
});
it('renders packages list', () => {
const packagesEl = vm.$el.querySelector('.license-packages');
expect(packagesEl).not.toBeNull();
expect(trimText(packagesEl.innerText)).toBe('Used by pg, puma, foo, and 2 more');
});
......
......@@ -61,11 +61,13 @@ describe('LicenseManagementRow', () => {
describe('template', () => {
it('first dropdown element should have a visible icon', () => {
const firstOption = vm.$el.querySelector('.dropdown-item:nth-child(1) svg');
expect(firstOption.classList).toContain(visibleClass);
});
it('second dropdown element should have no visible icon', () => {
const secondOption = vm.$el.querySelector('.dropdown-item:nth-child(2) svg');
expect(secondOption.classList).toContain(invisibleClass);
});
});
......@@ -94,11 +96,13 @@ describe('LicenseManagementRow', () => {
describe('template', () => {
it('first dropdown element should have no visible icon', () => {
const firstOption = vm.$el.querySelector('.dropdown-item:nth-child(1) svg');
expect(firstOption.classList).toContain(invisibleClass);
});
it('second dropdown element should have a visible icon', () => {
const secondOption = vm.$el.querySelector('.dropdown-item:nth-child(2) svg');
expect(secondOption.classList).toContain(visibleClass);
});
});
......@@ -108,18 +112,21 @@ describe('LicenseManagementRow', () => {
it('triggering setLicenseInModal by clicking the cancel button', () => {
const linkEl = vm.$el.querySelector('.js-remove-button');
linkEl.click();
expect(actions.setLicenseInModal).toHaveBeenCalled();
});
it('triggering approveLicense by clicking the first dropdown option', () => {
const linkEl = vm.$el.querySelector('.dropdown-item:nth-child(1)');
linkEl.click();
expect(actions.approveLicense).toHaveBeenCalled();
});
it('triggering approveLicense blacklistLicense by clicking the second dropdown option', () => {
const linkEl = vm.$el.querySelector('.dropdown-item:nth-child(2)');
linkEl.click();
expect(actions.blacklistLicense).toHaveBeenCalled();
});
});
......@@ -131,34 +138,41 @@ describe('LicenseManagementRow', () => {
it('renders status icon', () => {
const iconEl = vm.$el.querySelector('.report-block-list-icon');
expect(iconEl).not.toBeNull();
});
it('renders license name', () => {
const nameEl = vm.$el.querySelector('.js-license-name');
expect(nameEl.innerText.trim()).toBe(approvedLicense.name);
});
it('renders the removal button', () => {
const buttonEl = vm.$el.querySelector('.js-remove-button');
expect(buttonEl).not.toBeNull();
expect(buttonEl.querySelector('.ic-remove')).not.toBeNull();
});
it('renders computed property dropdownText into dropdown toggle', () => {
const dropdownEl = vm.$el.querySelector('.dropdown [data-toggle="dropdown"]');
expect(dropdownEl.innerText.trim()).toBe(vm.dropdownText);
});
it('renders the dropdown with `Approved` and `Blacklisted` options', () => {
const dropdownEl = vm.$el.querySelector('.dropdown');
expect(dropdownEl).not.toBeNull();
const firstOption = dropdownEl.querySelector('.dropdown-item:nth-child(1)');
expect(firstOption).not.toBeNull();
expect(firstOption.innerText.trim()).toBe('Approved');
const secondOption = dropdownEl.querySelector('.dropdown-item:nth-child(2)');
expect(secondOption).not.toBeNull();
expect(secondOption.innerText.trim()).toBe('Blacklisted');
});
......
......@@ -46,6 +46,7 @@ describe('LicensePackages', () => {
it('sets value of `showAllPackages` prop to true', () => {
vm.showAllPackages = false;
vm.handleShowPackages();
expect(vm.showAllPackages).toBe(true);
});
});
......@@ -54,12 +55,14 @@ describe('LicensePackages', () => {
describe('template', () => {
it('renders packages list for a particular license', () => {
const packagesEl = vm.$el.querySelector('.js-license-dependencies');
expect(packagesEl).not.toBeNull();
expect(packagesEl.innerText.trim()).toBe('Used by pg, puma, foo, and');
});
it('renders more packages button element', () => {
const buttonEl = vm.$el.querySelector('.btn-show-all-packages');
expect(buttonEl).not.toBeNull();
expect(buttonEl.innerText.trim()).toBe('2 more');
});
......
......@@ -65,17 +65,20 @@ describe('SetApprovalModal', () => {
describe('template correctly', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('Blacklist license?');
});
it('renders no Approve button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).toBeNull();
});
it('renders Blacklist button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Blacklist license');
});
......@@ -111,18 +114,21 @@ describe('SetApprovalModal', () => {
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('Approve license?');
});
it('renders Approve button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Approve license');
});
it('renders Blacklist button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Blacklist license');
});
......@@ -158,18 +164,21 @@ describe('SetApprovalModal', () => {
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('Approve license?');
});
it('renders Approve button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Approve license');
});
it('renders no Blacklist button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).toBeNull();
});
});
......@@ -204,17 +213,20 @@ describe('SetApprovalModal', () => {
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('License details');
});
it('renders no Approve button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).toBeNull();
});
it('renders no Blacklist button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).toBeNull();
});
});
......@@ -223,22 +235,26 @@ describe('SetApprovalModal', () => {
describe('Modal Body', () => {
it('renders the license name', () => {
const licenseName = vm.$el.querySelector('.js-license-name');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe(`License: ${licenseReport[0].name}`);
});
it('renders the license url with link', () => {
const licenseName = vm.$el.querySelector('.js-license-url');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe(`URL: ${licenseReport[0].url}`);
const licenseLink = licenseName.querySelector('a');
expect(licenseLink.getAttribute('href')).toBe(licenseReport[0].url);
expect(trimText(licenseLink.innerText)).toBe(licenseReport[0].url);
});
it('renders the license url', () => {
const licenseName = vm.$el.querySelector('.js-license-packages');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe('Packages: Used by pg, puma, foo, and 2 more');
});
......@@ -249,12 +265,14 @@ describe('SetApprovalModal', () => {
it('by clicking the cancel button', () => {
const linkEl = vm.$el.querySelector('.js-modal-cancel-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
it('triggering resetLicenseInModal by clicking the X button', () => {
const linkEl = vm.$el.querySelector('.js-modal-close-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
});
......@@ -263,6 +281,7 @@ describe('SetApprovalModal', () => {
it('by clicking the confirmation button', () => {
const linkEl = vm.$el.querySelector('.js-modal-primary-action');
linkEl.click();
expect(actions.approveLicense).toHaveBeenCalledWith(
jasmine.any(Object),
store.state.currentLicenseInModal,
......@@ -275,6 +294,7 @@ describe('SetApprovalModal', () => {
it('by clicking the confirmation button', () => {
const linkEl = vm.$el.querySelector('.js-modal-secondary-action');
linkEl.click();
expect(actions.blacklistLicense).toHaveBeenCalledWith(
jasmine.any(Object),
store.state.currentLicenseInModal,
......
......@@ -40,8 +40,10 @@ describe('LicenseManagement', () => {
return Vue.nextTick().then(() => {
const formEl = vm.$el.querySelector('.js-add-license-form');
expect(formEl).not.toBeNull();
const buttonEl = vm.$el.querySelector('.js-open-form');
expect(buttonEl).toBeNull();
done();
}).catch(done.fail);
......@@ -52,8 +54,10 @@ describe('LicenseManagement', () => {
return Vue.nextTick().then(() => {
const formEl = vm.$el.querySelector('.js-add-license-form');
expect(formEl).toBeNull();
const buttonEl = vm.$el.querySelector('.js-open-form');
expect(buttonEl).not.toBeNull();
done();
}).catch(done.fail);
......@@ -61,6 +65,7 @@ describe('LicenseManagement', () => {
it('clicking the Add a license button opens the form', () => {
const linkEl = vm.$el.querySelector('.js-open-form');
expect(vm.formIsOpen).toBe(false);
linkEl.click();
......@@ -83,6 +88,7 @@ describe('LicenseManagement', () => {
return Vue.nextTick().then(() => {
const callout = vm.$el.querySelector('.bs-callout');
expect(callout).not.toBeNull();
expect(trimText(callout.innerText)).toBe(vm.$options.emptyMessage);
done();
......@@ -116,6 +122,7 @@ describe('LicenseManagement', () => {
{ apiUrlManageLicenses: apiUrl },
undefined,
);
expect(actions.loadManagedLicenses).toHaveBeenCalledWith(
jasmine.any(Object),
undefined,
......
......@@ -171,6 +171,7 @@ describe('License Report MR Widget', () => {
it('should be rendered when fullReportPath prop is provided', () => {
const linkEl = vm.$el.querySelector(selector);
expect(linkEl).not.toBeNull();
expect(linkEl.getAttribute('href')).toEqual(defaultProps.fullReportPath);
expect(linkEl.textContent.trim()).toEqual('View full report');
......@@ -181,6 +182,7 @@ describe('License Report MR Widget', () => {
vm = mountComponent({ props });
const linkEl = vm.$el.querySelector(selector);
expect(linkEl).toBeNull();
});
});
......@@ -190,6 +192,7 @@ describe('License Report MR Widget', () => {
it('should be rendered when licenseManagementSettingsPath prop is provided', () => {
const linkEl = vm.$el.querySelector(selector);
expect(linkEl).not.toBeNull();
expect(linkEl.getAttribute('href')).toEqual(defaultProps.licenseManagementSettingsPath);
expect(linkEl.textContent.trim()).toEqual('Manage licenses');
......@@ -200,6 +203,7 @@ describe('License Report MR Widget', () => {
vm = mountComponent({ props });
const linkEl = vm.$el.querySelector(selector);
expect(linkEl).toBeNull();
});
});
......@@ -226,11 +230,13 @@ describe('License Report MR Widget', () => {
},
undefined,
);
expect(actions.loadManagedLicenses).toHaveBeenCalledWith(
jasmine.any(Object),
undefined,
undefined,
);
expect(actions.loadLicenseReport).toHaveBeenCalledWith(
jasmine.any(Object),
undefined,
......
......@@ -229,6 +229,7 @@ describe('License store actions', () => {
it('dispatches requestSetLicenseApproval and receiveSetLicenseApproval for successful response', done => {
putEndpointMock.replyOnce(req => {
const { approval_status, name } = JSON.parse(req.data);
expect(req.url).toBe(apiUrlManageLicenses);
expect(approval_status).toBe(newStatus);
expect(name).toBe(name);
......@@ -280,6 +281,7 @@ describe('License store actions', () => {
patchEndpointMock.replyOnce(req => {
expect(req.url).toBe(licenseUrl);
const { approval_status, name } = JSON.parse(req.data);
expect(approval_status).toBe(newStatus);
expect(name).toBeUndefined();
return [200, ''];
......
......@@ -14,15 +14,19 @@ describe('getters', () => {
const state = {};
state.isLoadingManagedLicenses = true;
state.isLoadingLicenseReport = true;
expect(getters.isLoading(state)).toBe(true);
state.isLoadingManagedLicenses = false;
state.isLoadingLicenseReport = true;
expect(getters.isLoading(state)).toBe(true);
state.isLoadingManagedLicenses = true;
state.isLoadingLicenseReport = false;
expect(getters.isLoading(state)).toBe(true);
state.isLoadingManagedLicenses = false;
state.isLoadingLicenseReport = false;
expect(getters.isLoading(state)).toBe(false);
});
});
......@@ -30,6 +34,7 @@ describe('getters', () => {
describe('licenseReport', () => {
it('returns empty array, if the reports are empty', () => {
const state = { headReport: {}, baseReport: {}, managedLicenses: [] };
expect(getters.licenseReport(state)).toEqual([]);
});
......@@ -57,6 +62,7 @@ describe('getters', () => {
it('should be `Loading license management report` text if isLoading', () => {
const mockGetters = {};
mockGetters.isLoading = true;
expect(getters.licenseSummaryText(state, mockGetters)).toBe(
'Loading license management report',
);
......@@ -64,6 +70,7 @@ describe('getters', () => {
it('should be `Failed to load license management report` text if an error has happened', () => {
const mockGetters = {};
expect(
getters.licenseSummaryText({ loadLicenseReportError: new Error('Test') }, mockGetters),
).toBe('Failed to load license management report');
......@@ -71,6 +78,7 @@ describe('getters', () => {
it('should be `License management detected no new licenses`, if the report is empty', () => {
const mockGetters = { licenseReport: [] };
expect(getters.licenseSummaryText(state, mockGetters)).toBe(
'License management detected no new licenses',
);
......@@ -78,6 +86,7 @@ describe('getters', () => {
it('should be `License management detected 1 new license`, if the report has one element', () => {
const mockGetters = { licenseReport: [licenseReportMock[0]] };
expect(getters.licenseSummaryText(state, mockGetters)).toBe(
'License management detected 1 new license',
);
......@@ -85,6 +94,7 @@ describe('getters', () => {
it('should be `License management detected 2 new licenses`, if the report has two elements', () => {
const mockGetters = { licenseReport: [licenseReportMock[0], licenseReportMock[0]] };
expect(getters.licenseSummaryText(state, mockGetters)).toBe(
'License management detected 2 new licenses',
);
......
......@@ -145,6 +145,7 @@ describe('License store mutations', () => {
expect(store.state.managedLicenses).toEqual([
{ name: 'Foo', approvalStatus: LICENSE_APPROVAL_STATUS.approved },
]);
expect(store.state.isLoadingManagedLicenses).toBe(false);
expect(store.state.loadManagedLicensesError).toBe(false);
});
......
......@@ -23,18 +23,21 @@ describe('utils', () => {
describe('parseLicenseReportMetrics', () => {
it('should return empty result, if no parameters are given', () => {
const result = parseLicenseReportMetrics();
expect(result).toEqual(jasmine.any(Array));
expect(result.length).toEqual(0);
});
it('should return empty result, if license head report is empty', () => {
const result = parseLicenseReportMetrics({ licenses: [] }, licenseBaseIssues);
expect(result).toEqual(jasmine.any(Array));
expect(result.length).toEqual(0);
});
it('should parse the received issues', () => {
const result = parseLicenseReportMetrics(licenseHeadIssues, licenseBaseIssues);
expect(result[0].name).toBe(licenseHeadIssues.licenses[0].name);
expect(result[0].url).toBe(licenseHeadIssues.dependencies[0].license.url);
});
......@@ -42,6 +45,7 @@ describe('utils', () => {
it('should omit issues from base report', () => {
const knownLicenseName = licenseBaseIssues.licenses[0].name;
const result = parseLicenseReportMetrics(licenseHeadIssues, licenseBaseIssues);
expect(result.length).toBe(licenseHeadIssues.licenses.length - 1);
expect(result[0].packages.length).toBe(licenseHeadIssues.dependencies.length - 1);
result.forEach(license => {
......@@ -54,6 +58,7 @@ describe('utils', () => {
approvedLicense,
blacklistedLicense,
]);
expect(result.length).toBe(2);
expect(result[0].approvalStatus).toBe(approvedLicense.approvalStatus);
expect(result[0].id).toBe(approvedLicense.id);
......@@ -81,6 +86,7 @@ describe('utils', () => {
it('should convert `approval_status` to `approvalStatus`', () => {
const src = { name: 'Foo', approval_status: 'approved', id: 3 };
const result = normalizeLicense(src);
expect(result.approvalStatus).toBe(src.approval_status);
expect(result.approval_status).toBe(undefined);
expect(result.name).toBe(src.name);
......
......@@ -29,11 +29,13 @@ describe('Linked pipeline', function() {
it('should render a link', () => {
const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-content');
expect(linkElement).not.toBeNull();
});
it('should link to the correct path', () => {
const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-content');
expect(linkElement.getAttribute('href')).toBe(this.propsData.pipelinePath);
});
......@@ -41,22 +43,26 @@ describe('Linked pipeline', function() {
const projectNameElement = this.linkedPipeline.$el.querySelector(
'.linked-pipeline-project-name',
);
expect(projectNameElement.innerText).toContain(this.propsData.projectName);
});
it('should render an svg within the status container', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.querySelector('svg')).not.toBeNull();
});
it('should render the pipeline status icon svg', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.querySelector('.ci-status-icon-running')).not.toBeNull();
expect(pipelineStatusElement.innerHTML).toContain('<svg');
});
it('should render the correct pipeline status icon style selector', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.firstChild.classList.contains('ci-status-icon-running')).toBe(
true,
);
......@@ -64,12 +70,14 @@ describe('Linked pipeline', function() {
it('should have a ci-status child component', () => {
const ciStatusComponent = this.linkedPipeline.$children[0];
expect(ciStatusComponent).toBeDefined();
expect(ciStatusComponent.$el.classList.contains('ci-status-icon')).toBe(true);
});
it('should render the pipeline id', () => {
const pipelineIdElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-id');
expect(pipelineIdElement.innerText).toContain(`#${this.propsData.pipelineId}`);
});
......
......@@ -25,6 +25,7 @@ describe('Linked Pipelines Column', function() {
const titleElement = this.linkedPipelinesColumn.$el.querySelector(
'.linked-pipelines-column-title',
);
expect(titleElement.innerText).toContain(this.propsData.columnTitle);
});
......@@ -36,6 +37,7 @@ describe('Linked Pipelines Column', function() {
const linkedPipelineElements = this.linkedPipelinesColumn.$el.querySelectorAll(
'.linked-pipeline',
);
expect(linkedPipelineElements.length).toBe(this.propsData.linkedPipelines.length);
});
});
......@@ -63,6 +63,7 @@ describe('ServiceDeskSetting', () => {
it('renders a copy to clipboard button', () => {
const button = vm.$el.querySelector('.btn-clipboard');
expect(button).not.toBe(null);
expect(button.dataset.clipboardText).toBe(incomingEmail);
});
......@@ -113,6 +114,7 @@ describe('ServiceDeskSetting', () => {
checked: true,
},
});
expect(onCheckboxToggleSpy).toHaveBeenCalledWith(true);
});
......@@ -123,6 +125,7 @@ describe('ServiceDeskSetting', () => {
checked: false,
},
});
expect(onCheckboxToggleSpy).toHaveBeenCalledWith(false);
});
});
......
......@@ -85,6 +85,7 @@ describe('AppComponent', () => {
vm.isLoading = false;
vm.isEpicsListEmpty = false;
vm.hasError = false;
expect(vm.showRoadmap).toBe(true);
});
......@@ -92,14 +93,17 @@ describe('AppComponent', () => {
vm.isLoading = true;
vm.isEpicsListEmpty = false;
vm.hasError = false;
expect(vm.showRoadmap).toBe(false);
vm.isLoading = false;
vm.isEpicsListEmpty = true;
vm.hasError = false;
expect(vm.showRoadmap).toBe(false);
vm.isLoading = false;
vm.isEpicsListEmpty = false;
vm.hasError = true;
expect(vm.showRoadmap).toBe(false);
});
});
......@@ -124,6 +128,7 @@ describe('AppComponent', () => {
spyOn(vm.store, 'setEpics');
vm.fetchEpics();
expect(vm.hasError).toBe(false);
setTimeout(() => {
expect(vm.isLoading).toBe(false);
......@@ -137,6 +142,7 @@ describe('AppComponent', () => {
spyOn(vm.store, 'setEpics');
vm.fetchEpics();
expect(vm.isEpicsListEmpty).toBe(false);
setTimeout(() => {
expect(vm.isEpicsListEmpty).toBe(true);
......@@ -149,6 +155,7 @@ describe('AppComponent', () => {
mock.onGet(vm.service.epicsPath).reply(500, {});
vm.fetchEpics();
expect(vm.hasError).toBe(false);
setTimeout(() => {
expect(vm.hasError).toBe(true);
......
......@@ -41,6 +41,7 @@ describe('EpicItemTimelineComponent', () => {
describe('data', () => {
it('returns default data props', () => {
vm = createComponent({});
expect(vm.timelineBarReady).toBe(false);
expect(vm.timelineBarStyles).toBe('');
});
......@@ -50,6 +51,7 @@ describe('EpicItemTimelineComponent', () => {
describe('itemStyles', () => {
it('returns CSS min-width based on getCellWidth() method', () => {
vm = createComponent({});
expect(vm.itemStyles.width).toBe(`${mockItemWidth}px`);
});
});
......@@ -59,6 +61,7 @@ describe('EpicItemTimelineComponent', () => {
describe('getCellWidth', () => {
it('returns proportionate width based on timeframe length and shellWidth', () => {
vm = createComponent({});
expect(vm.getCellWidth()).toBe(240);
});
......@@ -66,6 +69,7 @@ describe('EpicItemTimelineComponent', () => {
vm = createComponent({
shellWidth: 1000,
});
expect(vm.getCellWidth()).toBe(TIMELINE_CELL_MIN_WIDTH);
});
});
......@@ -78,6 +82,7 @@ describe('EpicItemTimelineComponent', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarEndOffset()).toBe(TIMELINE_END_OFFSET_FULL);
});
......@@ -88,6 +93,7 @@ describe('EpicItemTimelineComponent', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarEndOffset()).toBe(TIMELINE_END_OFFSET_FULL);
});
......@@ -97,11 +103,13 @@ describe('EpicItemTimelineComponent', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarEndOffset()).toBe(TIMELINE_END_OFFSET_HALF);
});
it('returns 0 when both Epic startDate and endDate is defined and within range', () => {
vm = createComponent({});
expect(vm.getTimelineBarEndOffset()).toBe(0);
});
});
......@@ -113,6 +121,7 @@ describe('EpicItemTimelineComponent', () => {
timeframeItem: mockTimeframeMonths[1],
});
vm.renderTimelineBar();
expect(vm.timelineBarStyles).toBe('width: 1216px; left: 0;');
expect(vm.timelineBarReady).toBe(true);
});
......@@ -123,6 +132,7 @@ describe('EpicItemTimelineComponent', () => {
timeframeItem: mockTimeframeMonths[1],
});
vm.renderTimelineBar();
expect(vm.timelineBarStyles).toBe('');
expect(vm.timelineBarReady).toBe(false);
});
......@@ -132,11 +142,13 @@ describe('EpicItemTimelineComponent', () => {
describe('template', () => {
it('renders component container element with class `epic-timeline-cell`', () => {
vm = createComponent({});
expect(vm.$el.classList.contains('epic-timeline-cell')).toBe(true);
});
it('renders component container element with `min-width` property applied via style attribute', () => {
vm = createComponent({});
expect(vm.$el.getAttribute('style')).toBe(`width: ${mockItemWidth}px;`);
});
......@@ -145,6 +157,7 @@ describe('EpicItemTimelineComponent', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeMonths[1] }),
timeframeItem: mockTimeframeMonths[1],
});
expect(vm.$el.querySelector('.timeline-bar-wrapper .timeline-bar')).not.toBeNull();
});
......
......@@ -41,6 +41,7 @@ describe('EpicsListSectionComponent', () => {
describe('data', () => {
it('returns default data props', () => {
vm = createComponent({});
expect(vm.shellHeight).toBe(0);
expect(vm.emptyRowHeight).toBe(0);
expect(vm.showEmptyRow).toBe(false);
......@@ -133,6 +134,7 @@ describe('EpicsListSectionComponent', () => {
it('scrolls table body to put timeline today indicator in focus', () => {
spyOn(vm.$el, 'scrollTo');
vm.scrollToTodayIndicator();
expect(vm.$el.scrollTo).toHaveBeenCalledWith(jasmine.any(Number), 0);
});
});
......
......@@ -36,6 +36,7 @@ describe('MonthsHeaderItemComponent', () => {
it('returns default data props', () => {
vm = createComponent({});
const currentDate = new Date();
expect(vm.currentDate.getDate()).toBe(currentDate.getDate());
expect(vm.currentYear).toBe(currentDate.getFullYear());
expect(vm.currentMonth).toBe(currentDate.getMonth());
......@@ -46,6 +47,7 @@ describe('MonthsHeaderItemComponent', () => {
describe('itemStyles', () => {
it('returns style object for container element based on value of `itemWidth` prop', () => {
vm = createComponent({});
expect(vm.itemStyles.width).toBe('180px');
});
});
......@@ -53,6 +55,7 @@ describe('MonthsHeaderItemComponent', () => {
describe('timelineHeaderLabel', () => {
it('returns string containing Year and Month for current timeline header item', () => {
vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Dec');
});
......@@ -61,6 +64,7 @@ describe('MonthsHeaderItemComponent', () => {
timeframeIndex: mockTimeframeIndex + 1,
timeframeItem: mockTimeframeMonths[mockTimeframeIndex + 1],
});
expect(vm.timelineHeaderLabel).toBe('2018 Jan');
});
});
......@@ -68,6 +72,7 @@ describe('MonthsHeaderItemComponent', () => {
describe('timelineHeaderClass', () => {
it('returns empty string when timeframeItem year or month is less than current year or month', () => {
vm = createComponent({});
expect(vm.timelineHeaderClass).toBe('');
});
......@@ -75,6 +80,7 @@ describe('MonthsHeaderItemComponent', () => {
vm = createComponent({
timeframeItem: new Date(),
});
expect(vm.timelineHeaderClass).toBe('label-dark label-bold');
});
......@@ -92,6 +98,7 @@ describe('MonthsHeaderItemComponent', () => {
vm.currentYear = mockTimeframeMonths[timeframeIndex].getFullYear();
vm.currentMonth = mockTimeframeMonths[timeframeIndex].getMonth() + 1;
expect(vm.timelineHeaderClass).toBe('label-dark');
});
});
......@@ -108,6 +115,7 @@ describe('MonthsHeaderItemComponent', () => {
it('renders item label element class `item-label` and value as `timelineHeaderLabel`', () => {
const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Dec');
});
......
......@@ -28,6 +28,7 @@ describe('MonthsHeaderSubItemComponent', () => {
describe('headerSubItems', () => {
it('returns array of dates containing Sundays from timeframeItem', () => {
vm = createComponent({});
expect(Array.isArray(vm.headerSubItems)).toBe(true);
vm.headerSubItems.forEach(subItem => {
expect(subItem instanceof Date).toBe(true);
......@@ -38,6 +39,7 @@ describe('MonthsHeaderSubItemComponent', () => {
describe('headerSubItemClass', () => {
it('returns string containing `label-dark` when timeframe year and month are greater than current year and month', () => {
vm = createComponent({});
expect(vm.headerSubItemClass).toBe('label-dark');
});
......@@ -46,6 +48,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate: new Date(2017, 10, 1), // Nov 1, 2017
timeframeItem: new Date(2018, 0, 1), // Jan 1, 2018
});
expect(vm.headerSubItemClass).toBe('');
});
});
......@@ -53,6 +56,7 @@ describe('MonthsHeaderSubItemComponent', () => {
describe('hasToday', () => {
it('returns true when current month and year is same as timeframe month and year', () => {
vm = createComponent({});
expect(vm.hasToday).toBe(true);
});
......@@ -61,6 +65,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate: new Date(2017, 10, 1), // Nov 1, 2017
timeframeItem: new Date(2018, 0, 1), // Jan 1, 2018
});
expect(vm.hasToday).toBe(false);
});
});
......@@ -73,6 +78,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate: new Date(2018, 0, 1), // Jan 1, 2018
});
const subItem = new Date(2018, 0, 15); // Jan 15, 2018
expect(vm.getSubItemValueClass(subItem)).toBe('label-dark');
});
});
......
......@@ -36,6 +36,7 @@ describe('QuartersHeaderItemComponent', () => {
it('returns default data props', () => {
vm = createComponent({});
const currentDate = new Date();
expect(vm.currentDate.getDate()).toBe(currentDate.getDate());
expect(vm.quarterBeginDate).toBe(mockTimeframeQuarters[mockTimeframeIndex].range[0]);
expect(vm.quarterEndDate).toBe(mockTimeframeQuarters[mockTimeframeIndex].range[2]);
......@@ -46,6 +47,7 @@ describe('QuartersHeaderItemComponent', () => {
describe('itemStyles', () => {
it('returns style object for container element based on value of `itemWidth` prop', () => {
vm = createComponent({});
expect(vm.itemStyles.width).toBe('180px');
});
});
......@@ -53,6 +55,7 @@ describe('QuartersHeaderItemComponent', () => {
describe('timelineHeaderLabel', () => {
it('returns string containing Year and Quarter for current timeline header item', () => {
vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Q4');
});
......@@ -61,6 +64,7 @@ describe('QuartersHeaderItemComponent', () => {
timeframeIndex: mockTimeframeIndex + 2,
timeframeItem: mockTimeframeQuarters[mockTimeframeIndex + 2],
});
expect(vm.timelineHeaderLabel).toBe('Q2');
});
});
......@@ -68,6 +72,7 @@ describe('QuartersHeaderItemComponent', () => {
describe('timelineHeaderClass', () => {
it('returns empty string when timeframeItem quarter is less than current quarter', () => {
vm = createComponent({});
expect(vm.timelineHeaderClass).toBe('');
});
......@@ -94,6 +99,7 @@ describe('QuartersHeaderItemComponent', () => {
});
[vm.currentDate] = mockTimeframeQuarters[0].range;
expect(vm.timelineHeaderClass).toBe('label-dark');
});
});
......@@ -110,6 +116,7 @@ describe('QuartersHeaderItemComponent', () => {
it('renders item label element class `item-label` and value as `timelineHeaderLabel`', () => {
const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Q4');
});
......
......@@ -28,6 +28,7 @@ describe('QuartersHeaderSubItemComponent', () => {
describe('headerSubItems', () => {
it('returns array of dates containing Months from timeframeItem', () => {
vm = createComponent({});
expect(Array.isArray(vm.headerSubItems)).toBe(true);
vm.headerSubItems.forEach(subItem => {
expect(subItem instanceof Date).toBe(true);
......@@ -38,6 +39,7 @@ describe('QuartersHeaderSubItemComponent', () => {
describe('hasToday', () => {
it('returns true when current quarter is same as timeframe quarter', () => {
vm = createComponent({});
expect(vm.hasToday).toBe(true);
});
......@@ -46,6 +48,7 @@ describe('QuartersHeaderSubItemComponent', () => {
currentDate: new Date(2017, 10, 1), // Nov 1, 2017
timeframeItem: mockTimeframeQuarters[1], // 2018 Apr May Jun
});
expect(vm.hasToday).toBe(false);
});
});
......@@ -58,6 +61,7 @@ describe('QuartersHeaderSubItemComponent', () => {
currentDate: new Date(2018, 0, 1), // Jan 1, 2018
});
const subItem = new Date(2018, 1, 15); // Feb 15, 2018
expect(vm.getSubItemValueClass(subItem)).toBe('label-dark');
});
});
......
......@@ -36,6 +36,7 @@ describe('WeeksHeaderItemComponent', () => {
it('returns default data props', () => {
vm = createComponent({});
const currentDate = new Date();
expect(vm.currentDate.getDate()).toBe(currentDate.getDate());
expect(vm.lastDayOfCurrentWeek.getDate()).toBe(
mockTimeframeWeeks[mockTimeframeIndex].getDate() + 7,
......@@ -47,6 +48,7 @@ describe('WeeksHeaderItemComponent', () => {
describe('itemStyles', () => {
it('returns style object for container element based on value of `itemWidth` prop', () => {
vm = createComponent({});
expect(vm.itemStyles.width).toBe('180px');
});
});
......@@ -54,6 +56,7 @@ describe('WeeksHeaderItemComponent', () => {
describe('timelineHeaderLabel', () => {
it('returns string containing Year, Month and Date for current timeline header item', () => {
vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Dec 24');
});
......@@ -62,6 +65,7 @@ describe('WeeksHeaderItemComponent', () => {
timeframeIndex: mockTimeframeIndex + 1,
timeframeItem: mockTimeframeWeeks[mockTimeframeIndex + 1],
});
expect(vm.timelineHeaderLabel).toBe('Dec 31');
});
});
......@@ -69,12 +73,14 @@ describe('WeeksHeaderItemComponent', () => {
describe('timelineHeaderClass', () => {
it('returns empty string when timeframeItem week is less than current week', () => {
vm = createComponent({});
expect(vm.timelineHeaderClass).toBe('');
});
it('returns string containing `label-dark label-bold` when current week is same as timeframeItem week', () => {
vm = createComponent({});
vm.currentDate = mockTimeframeWeeks[mockTimeframeIndex];
expect(vm.timelineHeaderClass).toBe('label-dark label-bold');
});
......@@ -87,6 +93,7 @@ describe('WeeksHeaderItemComponent', () => {
});
[vm.currentDate] = mockTimeframeWeeks;
expect(vm.timelineHeaderClass).toBe('label-dark');
});
});
......@@ -103,6 +110,7 @@ describe('WeeksHeaderItemComponent', () => {
it('renders item label element class `item-label` and value as `timelineHeaderLabel`', () => {
const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Dec 24');
});
......
......@@ -27,6 +27,7 @@ describe('MonthsHeaderSubItemComponent', () => {
describe('data', () => {
it('sets prop `headerSubItems` with array of dates containing days of week from timeframeItem', () => {
vm = createComponent({});
expect(Array.isArray(vm.headerSubItems)).toBe(true);
expect(vm.headerSubItems.length).toBe(7);
vm.headerSubItems.forEach(subItem => {
......@@ -39,6 +40,7 @@ describe('MonthsHeaderSubItemComponent', () => {
describe('hasToday', () => {
it('returns true when current week is same as timeframe week', () => {
vm = createComponent({});
expect(vm.hasToday).toBe(true);
});
......@@ -47,6 +49,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate: new Date(2017, 10, 1), // Nov 1, 2017
timeframeItem: new Date(2018, 0, 1), // Jan 1, 2018
});
expect(vm.hasToday).toBe(false);
});
});
......@@ -59,6 +62,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate: new Date(2018, 0, 1), // Jan 1, 2018
});
const subItem = new Date(2018, 0, 25); // Jan 25, 2018
expect(vm.getSubItemValueClass(subItem)).toBe('label-dark');
});
......@@ -68,6 +72,7 @@ describe('MonthsHeaderSubItemComponent', () => {
currentDate,
});
const subItem = currentDate;
expect(vm.getSubItemValueClass(subItem)).toBe('label-dark label-bold');
});
});
......
......@@ -71,11 +71,13 @@ describe('RoadmapShellComponent', () => {
describe('getWidthOffset', () => {
it('returns 0 when noScroll prop is true', () => {
vm.noScroll = true;
expect(vm.getWidthOffset()).toBe(0);
});
it('returns value of SCROLL_BAR_SIZE when noScroll prop is false', () => {
vm.noScroll = false;
expect(vm.getWidthOffset()).toBe(mockScrollBarSize);
});
});
......@@ -88,6 +90,7 @@ describe('RoadmapShellComponent', () => {
it('emits `epicsListScrolled` event via eventHub', () => {
vm.noScroll = false;
vm.handleScroll();
expect(eventHub.$emit).toHaveBeenCalledWith('epicsListScrolled', jasmine.any(Object));
});
});
......
......@@ -50,9 +50,11 @@ describe('RoadmapTimelineSectionComponent', () => {
// hence any value greater than 0 should
// update scrolledHeaderClass prop
vm.handleEpicsListScroll({ scrollTop: 1 });
expect(vm.scrolledHeaderClass).toBe('scroll-top-shadow');
vm.handleEpicsListScroll({ scrollTop: 0 });
expect(vm.scrolledHeaderClass).toBe('');
});
});
......@@ -62,6 +64,7 @@ describe('RoadmapTimelineSectionComponent', () => {
it('binds `epicsListScrolled` event listener via eventHub', () => {
spyOn(eventHub, '$on');
const vmX = createComponent({});
expect(eventHub.$on).toHaveBeenCalledWith('epicsListScrolled', jasmine.any(Function));
vmX.$destroy();
});
......@@ -72,6 +75,7 @@ describe('RoadmapTimelineSectionComponent', () => {
spyOn(eventHub, '$off');
const vmX = createComponent({});
vmX.$destroy();
expect(eventHub.$off).toHaveBeenCalledWith('epicsListScrolled', jasmine.any(Function));
});
});
......
......@@ -37,6 +37,7 @@ describe('TimelineTodayIndicatorComponent', () => {
describe('data', () => {
it('returns default data props', () => {
vm = createComponent({});
expect(vm.todayBarStyles).toBe('');
expect(vm.todayBarReady).toBe(false);
});
......@@ -50,6 +51,7 @@ describe('TimelineTodayIndicatorComponent', () => {
height: 100,
});
const stylesObj = vm.todayBarStyles;
expect(stylesObj.height).toBe('120px');
expect(stylesObj.left).toBe('48%');
expect(vm.todayBarReady).toBe(true);
......@@ -61,6 +63,7 @@ describe('TimelineTodayIndicatorComponent', () => {
it('binds `epicsListRendered` event listener via eventHub', () => {
spyOn(eventHub, '$on');
const vmX = createComponent({});
expect(eventHub.$on).toHaveBeenCalledWith('epicsListRendered', jasmine.any(Function));
vmX.$destroy();
});
......@@ -71,6 +74,7 @@ describe('TimelineTodayIndicatorComponent', () => {
spyOn(eventHub, '$off');
const vmX = createComponent({});
vmX.$destroy();
expect(eventHub.$off).toHaveBeenCalledWith('epicsListRendered', jasmine.any(Function));
});
});
......
......@@ -40,6 +40,7 @@ describe('MonthsPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeMonths[1] }),
timeframeItem: mockTimeframeMonths[1],
});
expect(vm.hasStartDateForMonth()).toBe(true);
});
......@@ -48,6 +49,7 @@ describe('MonthsPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeMonths[0] }),
timeframeItem: mockTimeframeMonths[1],
});
expect(vm.hasStartDateForMonth()).toBe(false);
});
});
......@@ -60,12 +62,14 @@ describe('MonthsPresetMixin', () => {
it('returns true if provided timeframeItem is under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 10); // Jan 10, 2018
const epicEndDate = new Date(2018, 0, 26); // Jan 26, 2018
expect(vm.isTimeframeUnderEndDateForMonth(timeframeItem, epicEndDate)).toBe(true);
});
it('returns false if provided timeframeItem is NOT under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 10); // Jan 10, 2018
const epicEndDate = new Date(2018, 1, 26); // Feb 26, 2018
expect(vm.isTimeframeUnderEndDateForMonth(timeframeItem, epicEndDate)).toBe(false);
});
});
......@@ -73,6 +77,7 @@ describe('MonthsPresetMixin', () => {
describe('getBarWidthForSingleMonth', () => {
it('returns calculated bar width based on provided cellWidth, daysInMonth and date', () => {
vm = createComponent({});
expect(vm.getBarWidthForSingleMonth(300, 30, 1)).toBe(10); // 10% size
expect(vm.getBarWidthForSingleMonth(300, 30, 15)).toBe(150); // 50% size
expect(vm.getBarWidthForSingleMonth(300, 30, 30)).toBe(300); // Full size
......@@ -84,6 +89,7 @@ describe('MonthsPresetMixin', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDateOutOfRange: true }),
});
expect(vm.getTimelineBarStartOffsetForMonths()).toBe('');
});
......@@ -94,6 +100,7 @@ describe('MonthsPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForMonths()).toBe('');
});
......@@ -103,6 +110,7 @@ describe('MonthsPresetMixin', () => {
startDate: new Date(2018, 0, 1),
}),
});
expect(vm.getTimelineBarStartOffsetForMonths()).toBe('left: 0;');
});
......@@ -113,6 +121,7 @@ describe('MonthsPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForMonths()).toBe('right: 8px;');
});
......@@ -122,6 +131,7 @@ describe('MonthsPresetMixin', () => {
startDate: new Date(2018, 0, 15),
}),
});
expect(vm.getTimelineBarStartOffsetForMonths()).toContain('left: 48');
});
});
......@@ -136,6 +146,7 @@ describe('MonthsPresetMixin', () => {
endDate: new Date(2018, 1, 15), // Feb 15, 2017
}),
});
expect(Math.floor(vm.getTimelineBarWidthForMonths())).toBe(492);
});
});
......
......@@ -40,6 +40,7 @@ describe('QuartersPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeQuarters[1].range[0] }),
timeframeItem: mockTimeframeQuarters[1],
});
expect(vm.hasStartDateForQuarter()).toBe(true);
});
......@@ -48,6 +49,7 @@ describe('QuartersPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeQuarters[0].range[0] }),
timeframeItem: mockTimeframeQuarters[1],
});
expect(vm.hasStartDateForQuarter()).toBe(false);
});
});
......@@ -60,12 +62,14 @@ describe('QuartersPresetMixin', () => {
it('returns true if provided timeframeItem is under epicEndDate', () => {
const timeframeItem = mockTimeframeQuarters[1];
const epicEndDate = mockTimeframeQuarters[1].range[2];
expect(vm.isTimeframeUnderEndDateForQuarter(timeframeItem, epicEndDate)).toBe(true);
});
it('returns false if provided timeframeItem is NOT under epicEndDate', () => {
const timeframeItem = mockTimeframeQuarters[1];
const epicEndDate = mockTimeframeQuarters[2].range[1];
expect(vm.isTimeframeUnderEndDateForQuarter(timeframeItem, epicEndDate)).toBe(false);
});
});
......@@ -73,6 +77,7 @@ describe('QuartersPresetMixin', () => {
describe('getBarWidthForSingleQuarter', () => {
it('returns calculated bar width based on provided cellWidth, daysInQuarter and day of quarter', () => {
vm = createComponent({});
expect(Math.floor(vm.getBarWidthForSingleQuarter(300, 91, 1))).toBe(3); // 10% size
expect(Math.floor(vm.getBarWidthForSingleQuarter(300, 91, 45))).toBe(148); // 50% size
expect(vm.getBarWidthForSingleQuarter(300, 91, 91)).toBe(300); // Full size
......@@ -84,6 +89,7 @@ describe('QuartersPresetMixin', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDateOutOfRange: true }),
});
expect(vm.getTimelineBarStartOffsetForQuarters()).toBe('');
});
......@@ -94,6 +100,7 @@ describe('QuartersPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForQuarters()).toBe('');
});
......@@ -103,6 +110,7 @@ describe('QuartersPresetMixin', () => {
startDate: mockTimeframeQuarters[0].range[0],
}),
});
expect(vm.getTimelineBarStartOffsetForQuarters()).toBe('left: 0;');
});
......@@ -113,6 +121,7 @@ describe('QuartersPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForQuarters()).toBe('right: 8px;');
});
......@@ -122,6 +131,7 @@ describe('QuartersPresetMixin', () => {
startDate: mockTimeframeQuarters[0].range[1],
}),
});
expect(vm.getTimelineBarStartOffsetForQuarters()).toContain('left: 34');
});
});
......@@ -136,6 +146,7 @@ describe('QuartersPresetMixin', () => {
endDate: mockTimeframeQuarters[1].range[1],
}),
});
expect(Math.floor(vm.getTimelineBarWidthForQuarters())).toBe(282);
});
});
......
......@@ -44,6 +44,7 @@ describe('SectionMixin', () => {
it('returns shellWidth after deducating value of SCROLL_BAR_SIZE when `listScrollable` prop is true', () => {
const vmScrollable = createComponent({ listScrollable: true });
expect(vmScrollable.sectionShellWidth).toBe(mockShellWidth - mockScrollBarSize);
vmScrollable.$destroy();
});
......
......@@ -40,6 +40,7 @@ describe('WeeksPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeWeeks[1] }),
timeframeItem: mockTimeframeWeeks[1],
});
expect(vm.hasStartDateForWeek()).toBe(true);
});
......@@ -48,6 +49,7 @@ describe('WeeksPresetMixin', () => {
epic: Object.assign({}, mockEpic, { startDate: mockTimeframeWeeks[0] }),
timeframeItem: mockTimeframeWeeks[1],
});
expect(vm.hasStartDateForWeek()).toBe(false);
});
});
......@@ -56,6 +58,7 @@ describe('WeeksPresetMixin', () => {
it('returns date object set to last day of the week from provided timeframeItem', () => {
vm = createComponent({});
const lastDayOfWeek = vm.getLastDayOfWeek(mockTimeframeWeeks[0]);
expect(lastDayOfWeek.getDate()).toBe(30);
expect(lastDayOfWeek.getMonth()).toBe(11);
expect(lastDayOfWeek.getFullYear()).toBe(2017);
......@@ -70,12 +73,14 @@ describe('WeeksPresetMixin', () => {
it('returns true if provided timeframeItem is under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 7); // Jan 7, 2018
const epicEndDate = new Date(2018, 0, 3); // Jan 3, 2018
expect(vm.isTimeframeUnderEndDateForWeek(timeframeItem, epicEndDate)).toBe(true);
});
it('returns false if provided timeframeItem is NOT under epicEndDate', () => {
const timeframeItem = new Date(2018, 0, 7); // Jan 7, 2018
const epicEndDate = new Date(2018, 0, 15); // Jan 15, 2018
expect(vm.isTimeframeUnderEndDateForWeek(timeframeItem, epicEndDate)).toBe(false);
});
});
......@@ -83,6 +88,7 @@ describe('WeeksPresetMixin', () => {
describe('getBarWidthForSingleWeek', () => {
it('returns calculated bar width based on provided cellWidth and day of week', () => {
vm = createComponent({});
expect(Math.floor(vm.getBarWidthForSingleWeek(300, 1))).toBe(42); // 10% size
expect(Math.floor(vm.getBarWidthForSingleWeek(300, 3))).toBe(128); // 50% size
expect(vm.getBarWidthForSingleWeek(300, 7)).toBe(300); // Full size
......@@ -92,6 +98,7 @@ describe('WeeksPresetMixin', () => {
describe('getTimelineBarEndOffsetHalfForWeek', () => {
it('returns timeline bar end offset for Weeks view', () => {
vm = createComponent({});
expect(vm.getTimelineBarEndOffsetHalfForWeek()).toBe(28);
});
});
......@@ -101,6 +108,7 @@ describe('WeeksPresetMixin', () => {
vm = createComponent({
epic: Object.assign({}, mockEpic, { startDateOutOfRange: true }),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('');
});
......@@ -111,6 +119,7 @@ describe('WeeksPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('');
});
......@@ -120,6 +129,7 @@ describe('WeeksPresetMixin', () => {
startDate: mockTimeframeWeeks[0],
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('left: 0;');
});
......@@ -132,6 +142,7 @@ describe('WeeksPresetMixin', () => {
endDateOutOfRange: true,
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toBe('right: 8px;');
});
......@@ -141,6 +152,7 @@ describe('WeeksPresetMixin', () => {
startDate: new Date(2018, 0, 15),
}),
});
expect(vm.getTimelineBarStartOffsetForWeeks()).toContain('left: 60');
});
});
......@@ -155,6 +167,7 @@ describe('WeeksPresetMixin', () => {
endDate: new Date(2018, 1, 2), // Feb 2, 2018
}),
});
expect(Math.floor(vm.getTimelineBarWidthForWeeks())).toBe(1600);
});
});
......
......@@ -14,6 +14,7 @@ describe('RoadmapService', () => {
it('returns axios instance for Epics path', () => {
spyOn(axios, 'get').and.stub();
service.getEpics();
expect(axios.get).toHaveBeenCalledWith(service.epicsPath);
});
});
......
......@@ -24,6 +24,7 @@ describe('RoadmapStore', () => {
describe('setEpics', () => {
it('sets Epics list to state while filtering out Epics with invalid dates', () => {
store.setEpics(rawEpics);
expect(store.getEpics().length).toBe(rawEpics.length - 2); // 2 epics have invalid dates
});
});
......@@ -45,6 +46,7 @@ describe('RoadmapStore', () => {
it('returns formatted Epic object from raw Epic object', () => {
const epic = RoadmapStore.formatEpicDetails(rawEpic);
expect(epic.id).toBe(rawEpic.id);
expect(epic.name).toBe(rawEpic.name);
expect(epic.groupId).toBe(rawEpic.group_id);
......@@ -60,6 +62,7 @@ describe('RoadmapStore', () => {
store.timeframeStartDate,
store.timeframeEndDate,
);
expect(epic.id).toBe(rawEpic.id);
expect(epic.startDateUndefined).toBe(true);
expect(epic.startDate.getTime()).toBe(store.timeframeStartDate.getTime());
......@@ -74,6 +77,7 @@ describe('RoadmapStore', () => {
store.timeframeStartDate,
store.timeframeEndDate,
);
expect(epic.id).toBe(rawEpic.id);
expect(epic.endDateUndefined).toBe(true);
expect(epic.endDate.getTime()).toBe(store.timeframeEndDate.getTime());
......@@ -89,6 +93,7 @@ describe('RoadmapStore', () => {
store.timeframeStartDate,
store.timeframeEndDate,
);
expect(epic.id).toBe(rawEpic.id);
expect(epic.startDateOutOfRange).toBe(true);
expect(epic.startDate.getTime()).toBe(store.timeframeStartDate.getTime());
......@@ -105,6 +110,7 @@ describe('RoadmapStore', () => {
store.timeframeStartDate,
store.timeframeEndDate,
);
expect(epic.id).toBe(rawEpic.id);
expect(epic.endDateOutOfRange).toBe(true);
expect(epic.endDate.getTime()).toBe(store.timeframeEndDate.getTime());
......
......@@ -20,11 +20,13 @@ describe('Vulnerability Count', () => {
it('should render the severity label', () => {
const header = vm.$el.querySelector('.vulnerability-count-header');
expect(header.textContent).toMatch(props.severity);
});
it('should render the count', () => {
const body = vm.$el.querySelector('.vulnerability-count-body');
expect(body.textContent).toMatch(props.count.toString());
});
});
......@@ -53,6 +53,7 @@ describe('Weight', function() {
expect(vm.$el.querySelector('.js-weight-collapsed-weight-label').textContent.trim()).toEqual(
`${WEIGHT}`,
);
expect(vm.$el.querySelector('.js-weight-weight-label-value').textContent.trim()).toEqual(
`${WEIGHT}`,
);
......@@ -69,6 +70,7 @@ describe('Weight', function() {
expect(vm.$el.querySelector('.js-weight-collapsed-weight-label').textContent.trim()).toEqual(
'None',
);
expect(vm.$el.querySelector('.js-weight-weight-label .no-value').textContent.trim()).toEqual(
'None',
);
......
......@@ -75,6 +75,7 @@ describe('Link To Members Components', () => {
Object.keys(correctVals).forEach(computedKey => {
const expectedVal = correctVals[computedKey];
const actualComputed = vm[computedKey];
expect(actualComputed).toBe(expectedVal);
});
});
......
......@@ -20,6 +20,7 @@ describe('Linked pipeline mini list', function() {
it('should render a linked pipeline with the correct href', () => {
const linkElement = this.component.$el.querySelector('.linked-pipeline-mini-item');
expect(linkElement.getAttribute('href')).toBe('/gitlab-org/gitlab-ce/pipelines/129');
});
......@@ -29,18 +30,21 @@ describe('Linked pipeline mini list', function() {
it('should render the correct ci status icon', () => {
const iconElement = this.component.$el.querySelector('.linked-pipeline-mini-item');
expect(iconElement.classList.contains('ci-status-icon-running')).toBe(true);
expect(iconElement.innerHTML).toContain('<svg');
});
it('should render an arrow icon', () => {
const iconElement = this.component.$el.querySelector('.arrow-icon');
expect(iconElement).not.toBeNull();
expect(iconElement.innerHTML).toContain('long-arrow');
});
it('should have an activated tooltip', () => {
const itemElement = this.component.$el.querySelector('.linked-pipeline-mini-item');
expect(itemElement.getAttribute('data-original-title')).toBe('GitLabCE - running');
});
......@@ -81,18 +85,21 @@ describe('Linked pipeline mini list', function() {
it('should render the correct ci status icon', () => {
const iconElement = this.component.$el.querySelector('.linked-pipeline-mini-item');
expect(iconElement.classList.contains('ci-status-icon-running')).toBe(true);
expect(iconElement.innerHTML).toContain('<svg');
});
it('should render an arrow icon', () => {
const iconElement = this.component.$el.querySelector('.arrow-icon');
expect(iconElement).not.toBeNull();
expect(iconElement.innerHTML).toContain('long-arrow');
});
it('should have prepped tooltips', () => {
const itemElement = this.component.$el.querySelectorAll('.linked-pipeline-mini-item')[2];
expect(itemElement.getAttribute('data-original-title')).toBe('GitLabCE - running');
});
......
......@@ -131,6 +131,7 @@ describe('Report issues', () => {
expect(
vm.$el.querySelector('.report-block-list li').textContent.trim(),
).toContain(dockerReportParsed.unapproved[0].path);
expect(
vm.$el.querySelector('.report-block-list li').textContent.trim(),
).toContain('in');
......
......@@ -98,6 +98,7 @@ describe('Card security reports app', () => {
expect(userAvatarLink.querySelector('img').getAttribute('src')).toBe(
`${TEST_HOST}/img?width=24`,
);
expect(userAvatarLink.textContent).toBe('TestUser');
});
......
......@@ -133,6 +133,7 @@ describe('Security Reports modal', () => {
expect(instances[0].textContent).toContain(
'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
);
expect(instances[1].textContent).toContain(
'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
);
......
......@@ -122,6 +122,7 @@ describe('sast issue body', () => {
expect(vm.$el.querySelector('a').getAttribute('href')).toEqual(
sastIssue.urlPath,
);
expect(vm.$el.querySelector('a').textContent.trim()).toEqual(
sastIssue.path,
);
......
......@@ -72,12 +72,14 @@ describe('Grouped security reports app', () => {
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning failed loading any results',
);
expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand');
expect(trimText(vm.$el.textContent)).toContain('SAST: Loading resulted in an error');
expect(trimText(vm.$el.textContent)).toContain(
'Dependency scanning: Loading resulted in an error',
);
expect(vm.$el.textContent).toContain('Container scanning: Loading resulted in an error');
expect(vm.$el.textContent).toContain('DAST: Loading resulted in an error');
done();
......@@ -125,6 +127,7 @@ describe('Grouped security reports app', () => {
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning is loading',
);
expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand');
expect(vm.$el.textContent).toContain('SAST is loading');
......@@ -212,6 +215,7 @@ describe('Grouped security reports app', () => {
expect(vm.$el.querySelector('.modal-title').textContent.trim()).toEqual(
sastIssues[0].message,
);
expect(vm.$el.querySelector('.modal-body').textContent).toContain(sastIssues[0].solution);
done();
......
......@@ -234,6 +234,7 @@ describe('Security reports getters', () => {
newState.dast.paths.head = 'foo';
newState.dast.paths.base = 'foo';
newState.dast.resolvedIssues = [{}];
expect(groupedDastText(newState)).toEqual('DAST detected 1 fixed vulnerability');
});
});
......@@ -272,6 +273,7 @@ describe('Security reports getters', () => {
newState.dependencyScanning.paths.head = 'foo';
newState.dependencyScanning.paths.base = 'foo';
newState.dependencyScanning.newIssues = [{}];
expect(groupedDependencyText(newState)).toEqual(
'Dependency scanning detected 1 new vulnerability',
);
......@@ -299,6 +301,7 @@ describe('Security reports getters', () => {
newState.dependencyScanning.paths.base = 'foo';
newState.dependencyScanning.resolvedIssues = [{}];
expect(groupedDependencyText(newState)).toEqual(
'Dependency scanning detected 1 fixed vulnerability',
);
......@@ -445,12 +448,14 @@ describe('Security reports getters', () => {
it('returns warning with new issues', () => {
const newState = state();
newState.sast.newIssues = [{}];
expect(sastStatusIcon(newState)).toEqual('warning');
});
it('returns warning with failed report', () => {
const newState = state();
newState.sast.hasError = true;
expect(sastStatusIcon(newState)).toEqual('warning');
});
......@@ -463,12 +468,14 @@ describe('Security reports getters', () => {
it('returns warning with new issues', () => {
const newState = state();
newState.dast.newIssues = [{}];
expect(dastStatusIcon(newState)).toEqual('warning');
});
it('returns warning with failed report', () => {
const newState = state();
newState.dast.hasError = true;
expect(dastStatusIcon(newState)).toEqual('warning');
});
......@@ -481,12 +488,14 @@ describe('Security reports getters', () => {
it('returns warning with new issues', () => {
const newState = state();
newState.sastContainer.newIssues = [{}];
expect(sastContainerStatusIcon(newState)).toEqual('warning');
});
it('returns warning with failed report', () => {
const newState = state();
newState.sastContainer.hasError = true;
expect(sastContainerStatusIcon(newState)).toEqual('warning');
});
......@@ -499,12 +508,14 @@ describe('Security reports getters', () => {
it('returns warning with new issues', () => {
const newState = state();
newState.dependencyScanning.newIssues = [{}];
expect(dependencyScanningStatusIcon(newState)).toEqual('warning');
});
it('returns warning with failed report', () => {
const newState = state();
newState.dependencyScanning.hasError = true;
expect(dependencyScanningStatusIcon(newState)).toEqual('warning');
});
......@@ -517,6 +528,7 @@ describe('Security reports getters', () => {
it('returns true when any report is loading', () => {
const newState = state();
newState.sast.isLoading = true;
expect(areReportsLoading(newState)).toEqual(true);
});
......@@ -572,6 +584,7 @@ describe('Security reports getters', () => {
it('returns false when any of the reports has base', () => {
const newState = state();
newState.sast.paths.base = 'foo';
expect(noBaseInAllReports(newState)).toEqual(false);
});
});
......
......@@ -48,6 +48,7 @@ describe('security reports mutations', () => {
describe('SET_VULNERABILITY_FEEDBACK_PATH', () => {
it('should set the vulnerabilities endpoint', () => {
mutations[types.SET_VULNERABILITY_FEEDBACK_PATH](stateCopy, 'vulnerability_path');
expect(stateCopy.vulnerabilityFeedbackPath).toEqual('vulnerability_path');
});
});
......@@ -55,6 +56,7 @@ describe('security reports mutations', () => {
describe('SET_VULNERABILITY_FEEDBACK_HELP_PATH', () => {
it('should set the vulnerabilities help path', () => {
mutations[types.SET_VULNERABILITY_FEEDBACK_HELP_PATH](stateCopy, 'vulnerability_help_path');
expect(stateCopy.vulnerabilityFeedbackHelpPath).toEqual('vulnerability_help_path');
});
});
......@@ -62,6 +64,7 @@ describe('security reports mutations', () => {
describe('SET_PIPELINE_ID', () => {
it('should set the pipeline id', () => {
mutations[types.SET_PIPELINE_ID](stateCopy, 123);
expect(stateCopy.pipelineId).toEqual(123);
});
});
......@@ -69,6 +72,7 @@ describe('security reports mutations', () => {
describe('SET_CAN_CREATE_ISSUE_PERMISSION', () => {
it('should set permission for create issue', () => {
mutations[types.SET_CAN_CREATE_ISSUE_PERMISSION](stateCopy, true);
expect(stateCopy.canCreateIssuePermission).toEqual(true);
});
});
......@@ -76,6 +80,7 @@ describe('security reports mutations', () => {
describe('SET_CAN_CREATE_FEEDBACK_PERMISSION', () => {
it('should set permission for create feedback', () => {
mutations[types.SET_CAN_CREATE_FEEDBACK_PERMISSION](stateCopy, true);
expect(stateCopy.canCreateFeedbackPermission).toEqual(true);
});
});
......@@ -139,6 +144,7 @@ describe('security reports mutations', () => {
describe('RECEIVE_SAST_REPORTS_ERROR', () => {
it('should set loading flag to false and error flag to true for sast', () => {
mutations[types.RECEIVE_SAST_REPORTS_ERROR](stateCopy);
expect(stateCopy.sast.isLoading).toEqual(false);
expect(stateCopy.sast.hasError).toEqual(true);
});
......@@ -306,6 +312,7 @@ describe('security reports mutations', () => {
expect(stateCopy.dependencyScanning.resolvedIssues).toEqual(
parsedDependencyScanningBaseStore,
);
expect(stateCopy.summaryCounts).toEqual({ added: 2, fixed: 1, existing: 1 });
});
});
......@@ -316,6 +323,7 @@ describe('security reports mutations', () => {
mutations[types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](stateCopy, {
head: dependencyScanningIssues,
});
expect(stateCopy.dependencyScanning.isLoading).toEqual(false);
expect(stateCopy.dependencyScanning.newIssues).toEqual(parsedDependencyScanningIssuesStore);
expect(stateCopy.summaryCounts).toEqual({ added: 3, fixed: 0, existing: 0 });
......@@ -448,6 +456,7 @@ describe('security reports mutations', () => {
describe('REQUEST_DISMISS_ISSUE', () => {
it('sets isDismissingIssue prop to true and resets error', () => {
mutations[types.REQUEST_DISMISS_ISSUE](stateCopy);
expect(stateCopy.modal.isDismissingIssue).toEqual(true);
expect(stateCopy.modal.error).toBeNull();
});
......@@ -456,6 +465,7 @@ describe('security reports mutations', () => {
describe('RECEIVE_DISMISS_ISSUE_SUCCESS', () => {
it('sets isDismissingIssue prop to false', () => {
mutations[types.RECEIVE_DISMISS_ISSUE_SUCCESS](stateCopy);
expect(stateCopy.modal.isDismissingIssue).toEqual(false);
});
});
......@@ -463,6 +473,7 @@ describe('security reports mutations', () => {
describe('RECEIVE_DISMISS_ISSUE_ERROR', () => {
it('sets isDismissingIssue prop to false and sets error', () => {
mutations[types.RECEIVE_DISMISS_ISSUE_ERROR](stateCopy, 'error');
expect(stateCopy.modal.isDismissingIssue).toEqual(false);
expect(stateCopy.modal.error).toEqual('error');
});
......@@ -471,6 +482,7 @@ describe('security reports mutations', () => {
describe('REQUEST_CREATE_ISSUE', () => {
it('sets isCreatingNewIssue prop to true and resets error', () => {
mutations[types.REQUEST_CREATE_ISSUE](stateCopy);
expect(stateCopy.modal.isCreatingNewIssue).toEqual(true);
expect(stateCopy.modal.error).toBeNull();
});
......@@ -479,6 +491,7 @@ describe('security reports mutations', () => {
describe('RECEIVE_CREATE_ISSUE_SUCCESS', () => {
it('sets isCreatingNewIssue prop to false', () => {
mutations[types.RECEIVE_CREATE_ISSUE_SUCCESS](stateCopy);
expect(stateCopy.modal.isCreatingNewIssue).toEqual(false);
});
});
......@@ -486,6 +499,7 @@ describe('security reports mutations', () => {
describe('RECEIVE_CREATE_ISSUE_ERROR', () => {
it('sets isCreatingNewIssue prop to false and sets error', () => {
mutations[types.RECEIVE_CREATE_ISSUE_ERROR](stateCopy, 'error');
expect(stateCopy.modal.isCreatingNewIssue).toEqual(false);
expect(stateCopy.modal.error).toEqual('error');
});
......@@ -502,6 +516,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_SAST_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sast.newIssues[0]).toEqual(updatedIssue);
});
......@@ -515,6 +530,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_SAST_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sast.resolvedIssues[0]).toEqual(updatedIssue);
});
......@@ -528,6 +544,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_SAST_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sast.allIssues[0]).toEqual(updatedIssue);
});
});
......@@ -543,6 +560,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.dependencyScanning.newIssues[0]).toEqual(updatedIssue);
});
......@@ -556,6 +574,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sast.resolvedIssues[0]).toEqual(updatedIssue);
});
......@@ -569,6 +588,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.dependencyScanning.allIssues[0]).toEqual(updatedIssue);
});
});
......@@ -584,6 +604,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_CONTAINER_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sastContainer.newIssues[0]).toEqual(updatedIssue);
});
......@@ -596,6 +617,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_CONTAINER_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sastContainer.resolvedIssues[0]).toEqual(updatedIssue);
});
});
......@@ -610,6 +632,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_DAST_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.dast.newIssues[0]).toEqual(updatedIssue);
});
......@@ -622,6 +645,7 @@ describe('security reports mutations', () => {
};
mutations[types.UPDATE_DAST_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.dast.resolvedIssues[0]).toEqual(updatedIssue);
});
});
......
......@@ -55,6 +55,7 @@ describe('security reports utils', () => {
describe('parseSastIssues', () => {
it('should parse the received issues with old JSON format', () => {
const parsed = parseSastIssues(oldSastIssues, [], 'path')[0];
expect(parsed.title).toEqual(sastIssues[0].message);
expect(parsed.path).toEqual(sastIssues[0].location.file);
expect(parsed.location.start_line).toEqual(sastIssues[0].location.start_line);
......@@ -65,6 +66,7 @@ describe('security reports utils', () => {
it('should parse the received issues with new JSON format', () => {
const parsed = parseSastIssues(sastIssues, [], 'path')[0];
expect(parsed.title).toEqual(sastIssues[0].message);
expect(parsed.path).toEqual(sastIssues[0].location.file);
expect(parsed.location.start_line).toEqual(sastIssues[0].location.start_line);
......@@ -75,6 +77,7 @@ describe('security reports utils', () => {
it('generate correct path to file when there is no line', () => {
const parsed = parseSastIssues(sastIssues, [], 'path')[1];
expect(parsed.urlPath).toEqual('path/Gemfile.lock');
});
......@@ -84,6 +87,7 @@ describe('security reports utils', () => {
sastFeedbacks,
'path',
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(sastFeedbacks[0]);
......@@ -94,6 +98,7 @@ describe('security reports utils', () => {
describe('parseDependencyScanningIssues', () => {
it('should parse the received issues', () => {
const parsed = parseDependencyScanningIssues(dependencyScanningIssues, [], 'path')[0];
expect(parsed.title).toEqual(dependencyScanningIssues[0].message);
expect(parsed.path).toEqual(dependencyScanningIssues[0].file);
expect(parsed.location.start_line).toEqual(sastIssues[0].location.start_line);
......@@ -104,6 +109,7 @@ describe('security reports utils', () => {
it('generate correct path to file when there is no line', () => {
const parsed = parseDependencyScanningIssues(dependencyScanningIssues, [], 'path')[1];
expect(parsed.urlPath).toEqual('path/Gemfile.lock');
});
......@@ -113,6 +119,7 @@ describe('security reports utils', () => {
cve: undefined,
}));
const parsed = parseDependencyScanningIssues(issuesWithoutCve, [], 'path')[0];
expect(parsed.project_fingerprint).toEqual(sha1(dependencyScanningIssues[0].message));
});
......@@ -122,6 +129,7 @@ describe('security reports utils', () => {
dependencyScanningFeedbacks,
'path',
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(dependencyScanningFeedbacks[0]);
......@@ -142,6 +150,7 @@ describe('security reports utils', () => {
value: issue.vulnerability,
url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${issue.vulnerability}`,
}]);
expect(parsed.project_fingerprint).toEqual(
sha1(`${issue.namespace}:${issue.vulnerability}:${issue.featurename}:${issue.featureversion}`));
});
......@@ -151,6 +160,7 @@ describe('security reports utils', () => {
dockerReport.vulnerabilities,
containerScanningFeedbacks,
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(containerScanningFeedbacks[0]);
......@@ -168,6 +178,7 @@ describe('security reports utils', () => {
dast.site.alerts,
dastFeedbacks,
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(dastFeedbacks[0]);
......@@ -234,6 +245,7 @@ describe('security reports utils', () => {
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 1, 0, 0)).toEqual(
' detected 1 new vulnerability',
);
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 2, 0, 0)).toEqual(
' detected 2 new vulnerabilities',
);
......@@ -245,6 +257,7 @@ describe('security reports utils', () => {
expect(
groupedTextBuilder('', { head: 'foo', base: 'foo' }, 1, 1, 0).replace(/\n+\s+/m, ' '),
).toEqual(' detected 1 new, and 1 fixed vulnerabilities');
expect(
groupedTextBuilder('', { head: 'foo', base: 'foo' }, 2, 2, 0).replace(/\n+\s+/m, ' '),
).toEqual(' detected 2 new, and 2 fixed vulnerabilities');
......@@ -256,6 +269,7 @@ describe('security reports utils', () => {
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 0, 1, 0)).toEqual(
' detected 1 fixed vulnerability',
);
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 0, 2, 0)).toEqual(
' detected 2 fixed vulnerabilities',
);
......
......@@ -36,5 +36,4 @@ rules:
- ignore:
- 'fixtures/blob'
# Temporarily disabled to facilitate an upgrade to eslint-plugin-jasmine
jasmine/new-line-before-expect: off
jasmine/prefer-toHaveBeenCalledWith: off
......@@ -42,6 +42,7 @@ describe('Ajax Loading Spinner', () => {
req.complete({});
const icon = ajaxLoadingSpinner.querySelector('i');
expect(icon).toHaveClass('fa-trash-o');
expect(icon).not.toHaveClass('fa-spinner');
expect(icon).not.toHaveClass('fa-spin');
......
......@@ -74,6 +74,7 @@ import '~/lib/utils/common_utils';
return lazyAssert(done, function() {
var $emojiMenu;
$emojiMenu = $('.emoji-menu');
expect($emojiMenu.length).toBe(1);
expect($emojiMenu.hasClass('is-visible')).toBe(true);
expect($emojiMenu.find('.js-emoji-menu-search').length).toBe(1);
......@@ -85,7 +86,8 @@ import '~/lib/utils/common_utils';
$('.js-add-award.note-action-button').click();
return lazyAssert(done, function() {
var $emojiMenu = $('.emoji-menu');
return expect($emojiMenu.length).toBe(1);
expect($emojiMenu.length).toBe(1);
});
});
......@@ -97,6 +99,7 @@ import '~/lib/utils/common_utils';
var $emojiMenu;
$emojiMenu = $('.emoji-menu');
$('body').click();
expect($emojiMenu.length).toBe(1);
expect($emojiMenu.hasClass('is-visible')).toBe(false);
return expect($('.js-awards-block.current').length).toBe(0);
......@@ -111,6 +114,7 @@ import '~/lib/utils/common_utils';
var $emojiMenu;
$emojiMenu = $('.emoji-menu');
$('.emoji-search').click();
expect($emojiMenu.length).toBe(1);
expect($emojiMenu.hasClass('is-visible')).toBe(true);
return expect($('.js-awards-block.current').length).toBe(1);
......@@ -124,6 +128,7 @@ import '~/lib/utils/common_utils';
$votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
$emojiButton = $votesBlock.find('[data-name=heart]');
expect($emojiButton.length).toBe(1);
expect($emojiButton.next('.js-counter').text()).toBe('1');
return expect($votesBlock.hasClass('hidden')).toBe(false);
......@@ -135,7 +140,8 @@ import '~/lib/utils/common_utils';
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
$emojiButton = $votesBlock.find('[data-name=heart]');
return expect($emojiButton.length).toBe(0);
expect($emojiButton.length).toBe(0);
});
return it('should decrement the emoji counter', function() {
var $emojiButton, $votesBlock;
......@@ -144,6 +150,7 @@ import '~/lib/utils/common_utils';
$emojiButton = $votesBlock.find('[data-name=heart]');
$emojiButton.next('.js-counter').text(5);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
expect($emojiButton.length).toBe(1);
return expect($emojiButton.next('.js-counter').text()).toBe('4');
});
......@@ -156,7 +163,8 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
$thumbsUpEmoji.attr('data-title', 'sam');
awardsHandler.userAuthored($thumbsUpEmoji);
return expect($thumbsUpEmoji.data('originalTitle')).toBe(
expect($thumbsUpEmoji.data('originalTitle')).toBe(
'You cannot vote on your own issue, MR and note',
);
});
......@@ -170,13 +178,15 @@ import '~/lib/utils/common_utils';
awardsHandler.userAuthored($thumbsUpEmoji);
jasmine.clock().tick(2801);
jasmine.clock().uninstall();
return expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
});
});
describe('::getAwardUrl', function() {
return it('returns the url for request', function() {
return expect(awardsHandler.getAwardUrl()).toBe(
expect(awardsHandler.getAwardUrl()).toBe(
'http://test.host/snippets/1/toggle_award_emoji',
);
});
......@@ -190,11 +200,13 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
$thumbsDownEmoji = $votesBlock.find('[data-name=thumbsdown]').parent();
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
expect($thumbsUpEmoji.hasClass('active')).toBe(true);
expect($thumbsDownEmoji.hasClass('active')).toBe(false);
$thumbsUpEmoji.tooltip();
$thumbsDownEmoji.tooltip();
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsdown', true);
expect($thumbsUpEmoji.hasClass('active')).toBe(false);
return expect($thumbsDownEmoji.hasClass('active')).toBe(true);
});
......@@ -206,9 +218,11 @@ import '~/lib/utils/common_utils';
awardUrl = awardsHandler.getAwardUrl();
$votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAward($votesBlock, awardUrl, 'fire', false);
expect($votesBlock.find('[data-name=fire]').length).toBe(1);
awardsHandler.removeEmoji($votesBlock.find('[data-name=fire]').closest('button'));
return expect($votesBlock.find('[data-name=fire]').length).toBe(0);
expect($votesBlock.find('[data-name=fire]').length).toBe(0);
});
});
......@@ -221,7 +235,8 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji.attr('data-title', 'sam, jerry, max, and andy');
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
$thumbsUpEmoji.tooltip();
return expect($thumbsUpEmoji.data('originalTitle')).toBe('You, sam, jerry, max, and andy');
expect($thumbsUpEmoji.data('originalTitle')).toBe('You, sam, jerry, max, and andy');
});
return it('handles the special case where "You" is not cleanly comma seperated', function() {
var $thumbsUpEmoji, $votesBlock, awardUrl;
......@@ -231,7 +246,8 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji.attr('data-title', 'sam');
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
$thumbsUpEmoji.tooltip();
return expect($thumbsUpEmoji.data('originalTitle')).toBe('You and sam');
expect($thumbsUpEmoji.data('originalTitle')).toBe('You and sam');
});
});
......@@ -245,7 +261,8 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji.addClass('active');
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
$thumbsUpEmoji.tooltip();
return expect($thumbsUpEmoji.data('originalTitle')).toBe('sam, jerry, max, and andy');
expect($thumbsUpEmoji.data('originalTitle')).toBe('sam, jerry, max, and andy');
});
return it('handles the special case where "You" is not cleanly comma seperated', function() {
var $thumbsUpEmoji, $votesBlock, awardUrl;
......@@ -256,7 +273,8 @@ import '~/lib/utils/common_utils';
$thumbsUpEmoji.addClass('active');
awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
$thumbsUpEmoji.tooltip();
return expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
});
});
......@@ -267,6 +285,7 @@ import '~/lib/utils/common_utils';
expect($('[data-name=angel]').is(':visible')).toBe(true);
expect($('[data-name=anger]').is(':visible')).toBe(true);
awardsHandler.searchEmojis('ali');
expect($('[data-name=angel]').is(':visible')).toBe(false);
expect($('[data-name=anger]').is(':visible')).toBe(false);
expect($('[data-name=alien]').is(':visible')).toBe(true);
......@@ -282,10 +301,12 @@ import '~/lib/utils/common_utils';
return openAndWaitForEmojiMenu()
.then(() => {
awardsHandler.searchEmojis('ali');
expect($('[data-name=angel]').is(':visible')).toBe(false);
expect($('[data-name=anger]').is(':visible')).toBe(false);
expect($('[data-name=alien]').is(':visible')).toBe(true);
awardsHandler.searchEmojis('');
expect($('[data-name=angel]').is(':visible')).toBe(true);
expect($('[data-name=anger]').is(':visible')).toBe(true);
expect($('[data-name=alien]').is(':visible')).toBe(true);
......@@ -309,6 +330,7 @@ import '~/lib/utils/common_utils';
expect($emoji.length).toBe(1);
expect($block.find(emojiSelector).length).toBe(0);
$emoji.click();
expect($menu.hasClass('.is-visible')).toBe(false);
expect($block.find(emojiSelector).length).toBe(1);
});
......@@ -332,6 +354,7 @@ import '~/lib/utils/common_utils';
`.emoji-menu-list:not(.frequent-emojis) ${emojiSelector}`,
);
$emoji.click();
expect($block.find(emojiSelector).length).toBe(0);
})
.then(done)
......
......@@ -66,8 +66,10 @@ describe('BadgeForm component', () => {
};
const expectInvalidInput = inputElementSelector => {
const inputElement = vm.$el.querySelector(inputElementSelector);
expect(inputElement).toBeMatchedBy(':invalid');
const feedbackElement = vm.$el.querySelector(`${inputElementSelector} + .invalid-feedback`);
expect(feedbackElement).toBeVisible();
};
......@@ -90,6 +92,7 @@ describe('BadgeForm component', () => {
submitForm();
expectInvalidInput(imageUrlSelector);
expect(vm[submitAction]).not.toHaveBeenCalled();
});
......@@ -99,6 +102,7 @@ describe('BadgeForm component', () => {
submitForm();
expectInvalidInput(imageUrlSelector);
expect(vm[submitAction]).not.toHaveBeenCalled();
});
......@@ -108,6 +112,7 @@ describe('BadgeForm component', () => {
submitForm();
expectInvalidInput(linkUrlSelector);
expect(vm[submitAction]).not.toHaveBeenCalled();
});
......@@ -117,6 +122,7 @@ describe('BadgeForm component', () => {
submitForm();
expectInvalidInput(linkUrlSelector);
expect(vm[submitAction]).not.toHaveBeenCalled();
});
......@@ -143,8 +149,10 @@ describe('BadgeForm component', () => {
it('renders one button', () => {
expect(vm.$el.querySelector('.row-content-block')).toBeNull();
const buttons = vm.$el.querySelectorAll('.form-group:last-of-type button');
expect(buttons.length).toBe(1);
const buttonAddElement = buttons[0];
expect(buttonAddElement).toBeVisible();
expect(buttonAddElement).toHaveText('Add badge');
});
......@@ -165,11 +173,14 @@ describe('BadgeForm component', () => {
it('renders two buttons', () => {
const buttons = vm.$el.querySelectorAll('.row-content-block button');
expect(buttons.length).toBe(2);
const buttonSaveElement = buttons[0];
expect(buttonSaveElement).toBeVisible();
expect(buttonSaveElement).toHaveText('Save changes');
const buttonCancelElement = buttons[1];
expect(buttonCancelElement).toBeVisible();
expect(buttonCancelElement).toHaveText('Cancel');
});
......
......@@ -34,6 +34,7 @@ describe('BadgeListRow component', () => {
it('renders the badge', () => {
const badgeElement = vm.$el.querySelector('.project-badge');
expect(badgeElement).not.toBeNull();
expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
});
......@@ -48,11 +49,14 @@ describe('BadgeListRow component', () => {
it('shows edit and delete buttons', () => {
const buttons = vm.$el.querySelectorAll('.table-button-footer button');
expect(buttons).toHaveLength(2);
const buttonEditElement = buttons[0];
expect(buttonEditElement).toBeVisible();
expect(buttonEditElement).toHaveSpriteIcon('pencil');
const buttonDeleteElement = buttons[1];
expect(buttonDeleteElement).toBeVisible();
expect(buttonDeleteElement).toHaveSpriteIcon('remove');
});
......@@ -91,6 +95,7 @@ describe('BadgeListRow component', () => {
it('hides edit and delete buttons', () => {
const buttons = vm.$el.querySelectorAll('.table-button-footer button');
expect(buttons).toHaveLength(0);
});
});
......
......@@ -34,11 +34,13 @@ describe('BadgeList component', () => {
it('renders a header with the badge count', () => {
const header = vm.$el.querySelector('.card-header');
expect(header).toHaveText(new RegExp(`Your badges\\s+${numberOfDummyBadges}`));
});
it('renders a row for each badge', () => {
const rows = vm.$el.querySelectorAll('.gl-responsive-table-row');
expect(rows).toHaveLength(numberOfDummyBadges);
});
......@@ -59,6 +61,7 @@ describe('BadgeList component', () => {
Vue.nextTick()
.then(() => {
const loadingIcon = vm.$el.querySelector('.fa-spinner');
expect(loadingIcon).toBeVisible();
})
.then(done)
......
......@@ -38,6 +38,7 @@ describe('BadgeSettings component', () => {
$(modal).on('shown.bs.modal', () => {
expect(modal).toContainText('Delete badge?');
const badgeElement = modal.querySelector('img.project-badge');
expect(badgeElement).not.toBe(null);
expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
......@@ -53,14 +54,17 @@ describe('BadgeSettings component', () => {
it('displays a form to add a badge', () => {
const form = vm.$el.querySelector('form:nth-of-type(2)');
expect(form).not.toBe(null);
const button = form.querySelector('.btn-success');
expect(button).not.toBe(null);
expect(button).toHaveText(/Add badge/);
});
it('displays badge list', () => {
const badgeListElement = vm.$el.querySelector('.card');
expect(badgeListElement).not.toBe(null);
expect(badgeListElement).toBeVisible();
expect(badgeListElement).toContainText('Your badges');
......@@ -77,17 +81,21 @@ describe('BadgeSettings component', () => {
it('displays a form to edit a badge', () => {
const form = vm.$el.querySelector('form:nth-of-type(1)');
expect(form).not.toBe(null);
const submitButton = form.querySelector('.btn-success');
expect(submitButton).not.toBe(null);
expect(submitButton).toHaveText(/Save changes/);
const cancelButton = form.querySelector('.btn-cancel');
expect(cancelButton).not.toBe(null);
expect(cancelButton).toHaveText(/Cancel/);
});
it('displays no badge list', () => {
const badgeListElement = vm.$el.querySelector('.card');
expect(badgeListElement).toBeHidden();
});
});
......@@ -102,6 +110,7 @@ describe('BadgeSettings component', () => {
deleteButton.click();
const badge = store.state.badgeInModal;
expect(vm.deleteBadge).toHaveBeenCalledWith(badge);
});
});
......
......@@ -107,6 +107,7 @@ describe('Badge component', () => {
expect(vm.isLoading).toBe(false);
expect(vm.hasError).toBe(false);
const { badgeImage, loadingIcon, reloadButton } = findElements();
expect(badgeImage).toBeVisible();
expect(loadingIcon).toBeHidden();
expect(reloadButton).toBeHidden();
......@@ -119,6 +120,7 @@ describe('Badge component', () => {
Vue.nextTick()
.then(() => {
const { badgeImage, loadingIcon, reloadButton } = findElements();
expect(badgeImage).toBeHidden();
expect(loadingIcon).toBeVisible();
expect(reloadButton).toBeHidden();
......@@ -134,6 +136,7 @@ describe('Badge component', () => {
Vue.nextTick()
.then(() => {
const { badgeImage, loadingIcon, reloadButton } = findElements();
expect(badgeImage).toBeHidden();
expect(loadingIcon).toBeHidden();
expect(reloadButton).toBeVisible();
......
......@@ -94,6 +94,7 @@ describe('Badges store actions', () => {
link_url: badgeInAddForm.linkUrl,
}),
);
expect(dispatch.calls.allArgs()).toEqual([['requestNewBadge']]);
dispatch.calls.reset();
return [200, dummyResponse];
......@@ -117,6 +118,7 @@ describe('Badges store actions', () => {
link_url: badgeInAddForm.linkUrl,
}),
);
expect(dispatch.calls.allArgs()).toEqual([['requestNewBadge']]);
dispatch.calls.reset();
return [500, ''];
......@@ -296,6 +298,7 @@ describe('Badges store actions', () => {
.loadBadges({ state, dispatch }, dummyData)
.then(() => {
const badges = dummyReponse.map(transformBackendBadge);
expect(dispatch.calls.allArgs()).toEqual([['receiveLoadBadges', badges]]);
})
.then(done)
......@@ -416,6 +419,7 @@ describe('Badges store actions', () => {
.then(() => {
expect(axios.get.calls.count()).toBe(1);
const url = axios.get.calls.argsFor(0)[0];
expect(url).toMatch(`^${dummyEndpointUrl}/render?`);
expect(url).toMatch('\\?link_url=%3Cscript%3EI%20am%20dangerous!%3C%2Fscript%3E&');
expect(url).toMatch('&image_url=%26make-sandwhich%3Dtrue$');
......@@ -436,6 +440,7 @@ describe('Badges store actions', () => {
.renderBadge({ state, dispatch })
.then(() => {
const renderedBadge = transformBackendBadge(dummyReponse);
expect(dispatch.calls.allArgs()).toEqual([['receiveRenderedBadge', renderedBadge]]);
})
.then(done)
......@@ -525,6 +530,7 @@ describe('Badges store actions', () => {
link_url: badgeInEditForm.linkUrl,
}),
);
expect(dispatch.calls.allArgs()).toEqual([['requestUpdatedBadge']]);
dispatch.calls.reset();
return [200, dummyResponse];
......@@ -548,6 +554,7 @@ describe('Badges store actions', () => {
link_url: badgeInEditForm.linkUrl,
}),
);
expect(dispatch.calls.allArgs()).toEqual([['requestUpdatedBadge']]);
dispatch.calls.reset();
return [500, ''];
......
......@@ -12,6 +12,7 @@ describe('Autosize behavior', () => {
it('does not overwrite the resize property', () => {
load();
expect($('textarea')).toHaveCss({
resize: 'vertical',
});
......
......@@ -29,6 +29,7 @@ describe('CopyAsGFM', () => {
it('wraps pasted code when not already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: ', '');
expect(insertedText).toEqual('`code`');
});
......@@ -38,6 +39,7 @@ describe('CopyAsGFM', () => {
it('does not wrap pasted code when already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: `', '`');
expect(insertedText).toEqual('code');
});
......@@ -86,6 +88,7 @@ describe('CopyAsGFM', () => {
simulateCopy();
const expectedGFM = '- List Item1\n- List Item2';
expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
});
......@@ -95,6 +98,7 @@ describe('CopyAsGFM', () => {
simulateCopy();
const expectedGFM = '1. List Item1\n1. List Item2';
expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
});
});
......
......@@ -30,6 +30,7 @@ describe('Quick Submit behavior', function () {
keyCode: 32,
}),
);
expect(this.spies.submit).not.toHaveBeenTriggered();
});
......@@ -40,6 +41,7 @@ describe('Quick Submit behavior', function () {
metaKey: false,
}),
);
expect(this.spies.submit).not.toHaveBeenTriggered();
});
......@@ -49,6 +51,7 @@ describe('Quick Submit behavior', function () {
repeat: true,
}),
);
expect(this.spies.submit).not.toHaveBeenTriggered();
});
......@@ -86,7 +89,8 @@ describe('Quick Submit behavior', function () {
describe('In Macintosh', () => {
it('responds to Meta+Enter', () => {
this.textarea.trigger(keydownEvent());
return expect(this.spies.submit).toHaveBeenTriggered();
expect(this.spies.submit).toHaveBeenTriggered();
});
it('excludes other modifier keys', () => {
......@@ -105,13 +109,15 @@ describe('Quick Submit behavior', function () {
shiftKey: true,
}),
);
return expect(this.spies.submit).not.toHaveBeenTriggered();
expect(this.spies.submit).not.toHaveBeenTriggered();
});
});
} else {
it('responds to Ctrl+Enter', () => {
this.textarea.trigger(keydownEvent());
return expect(this.spies.submit).toHaveBeenTriggered();
expect(this.spies.submit).toHaveBeenTriggered();
});
it('excludes other modifier keys', () => {
......@@ -130,7 +136,8 @@ describe('Quick Submit behavior', function () {
shiftKey: true,
}),
);
return expect(this.spies.submit).not.toHaveBeenTriggered();
expect(this.spies.submit).not.toHaveBeenTriggered();
});
}
});
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment