summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/boards/components/issue_time_estimate_spec.js81
-rw-r--r--spec/frontend/boards/issue_card_spec.js307
-rw-r--r--spec/frontend/jobs/components/log/log_spec.js4
-rw-r--r--spec/frontend/jobs/store/utils_spec.js20
-rw-r--r--spec/javascripts/boards/components/issue_time_estimate_spec.js70
-rw-r--r--spec/javascripts/boards/issue_card_spec.js294
6 files changed, 400 insertions, 376 deletions
diff --git a/spec/frontend/boards/components/issue_time_estimate_spec.js b/spec/frontend/boards/components/issue_time_estimate_spec.js
new file mode 100644
index 00000000000..0a16dfbc009
--- /dev/null
+++ b/spec/frontend/boards/components/issue_time_estimate_spec.js
@@ -0,0 +1,81 @@
+import IssueTimeEstimate from '~/boards/components/issue_time_estimate.vue';
+import boardsStore from '~/boards/stores/boards_store';
+import { shallowMount } from '@vue/test-utils';
+
+describe('Issue Time Estimate component', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ boardsStore.create();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when limitToHours is false', () => {
+ beforeEach(() => {
+ boardsStore.timeTracking.limitToHours = false;
+ wrapper = shallowMount(IssueTimeEstimate, {
+ propsData: {
+ estimate: 374460,
+ },
+ sync: false,
+ });
+ });
+
+ it('renders the correct time estimate', () => {
+ expect(
+ wrapper
+ .find('time')
+ .text()
+ .trim(),
+ ).toEqual('2w 3d 1m');
+ });
+
+ it('renders expanded time estimate in tooltip', () => {
+ expect(wrapper.find('.js-issue-time-estimate').text()).toContain('2 weeks 3 days 1 minute');
+ });
+
+ it('prevents tooltip xss', done => {
+ const alertSpy = jest.spyOn(window, 'alert');
+ wrapper.setProps({ estimate: 'Foo <script>alert("XSS")</script>' });
+ wrapper.vm.$nextTick(() => {
+ expect(alertSpy).not.toHaveBeenCalled();
+ expect(
+ wrapper
+ .find('time')
+ .text()
+ .trim(),
+ ).toEqual('0m');
+ expect(wrapper.find('.js-issue-time-estimate').text()).toContain('0m');
+ done();
+ });
+ });
+ });
+
+ describe('when limitToHours is true', () => {
+ beforeEach(() => {
+ boardsStore.timeTracking.limitToHours = true;
+ wrapper = shallowMount(IssueTimeEstimate, {
+ propsData: {
+ estimate: 374460,
+ },
+ sync: false,
+ });
+ });
+
+ it('renders the correct time estimate', () => {
+ expect(
+ wrapper
+ .find('time')
+ .text()
+ .trim(),
+ ).toEqual('104h 1m');
+ });
+
+ it('renders expanded time estimate in tooltip', () => {
+ expect(wrapper.find('.js-issue-time-estimate').text()).toContain('104 hours 1 minute');
+ });
+ });
+});
diff --git a/spec/frontend/boards/issue_card_spec.js b/spec/frontend/boards/issue_card_spec.js
new file mode 100644
index 00000000000..ebe97769ab7
--- /dev/null
+++ b/spec/frontend/boards/issue_card_spec.js
@@ -0,0 +1,307 @@
+/* global ListAssignee, ListLabel, ListIssue */
+import { mount } from '@vue/test-utils';
+import _ from 'underscore';
+import '~/boards/models/label';
+import '~/boards/models/assignee';
+import '~/boards/models/issue';
+import '~/boards/models/list';
+import IssueCardInner from '~/boards/components/issue_card_inner.vue';
+import { listObj } from '../../javascripts/boards/mock_data';
+import store from '~/boards/stores';
+
+describe('Issue card component', () => {
+ const user = new ListAssignee({
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ avatar: 'test_image',
+ });
+
+ const label1 = new ListLabel({
+ id: 3,
+ title: 'testing 123',
+ color: 'blue',
+ text_color: 'white',
+ description: 'test',
+ });
+
+ let wrapper;
+ let issue;
+ let list;
+
+ beforeEach(() => {
+ list = { ...listObj, type: 'label' };
+ issue = new ListIssue({
+ title: 'Testing',
+ id: 1,
+ iid: 1,
+ confidential: false,
+ labels: [list.label],
+ assignees: [],
+ reference_path: '#1',
+ real_path: '/test/1',
+ weight: 1,
+ });
+ wrapper = mount(IssueCardInner, {
+ propsData: {
+ list,
+ issue,
+ issueLinkBase: '/test',
+ rootPath: '/',
+ },
+ store,
+ sync: false,
+ });
+ });
+
+ it('renders issue title', () => {
+ expect(wrapper.find('.board-card-title').text()).toContain(issue.title);
+ });
+
+ it('includes issue base in link', () => {
+ expect(wrapper.find('.board-card-title a').attributes('href')).toContain('/test');
+ });
+
+ it('includes issue title on link', () => {
+ expect(wrapper.find('.board-card-title a').attributes('title')).toBe(issue.title);
+ });
+
+ it('does not render confidential icon', () => {
+ expect(wrapper.find('.fa-eye-flash').exists()).toBe(false);
+ });
+
+ it('renders confidential icon', done => {
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ confidential: true,
+ },
+ });
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('.confidential-icon').exists()).toBe(true);
+ done();
+ });
+ });
+
+ it('renders issue ID with #', () => {
+ expect(wrapper.find('.board-card-number').text()).toContain(`#${issue.id}`);
+ });
+
+ describe('assignee', () => {
+ it('does not render assignee', () => {
+ expect(wrapper.find('.board-card-assignee .avatar').exists()).toBe(false);
+ });
+
+ describe('exists', () => {
+ beforeEach(done => {
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ assignees: [user],
+ },
+ });
+
+ wrapper.vm.$nextTick(done);
+ });
+
+ it('renders assignee', () => {
+ expect(wrapper.find('.board-card-assignee .avatar').exists()).toBe(true);
+ });
+
+ it('sets title', () => {
+ expect(wrapper.find('.js-assignee-tooltip').text()).toContain(`${user.name}`);
+ });
+
+ it('sets users path', () => {
+ expect(wrapper.find('.board-card-assignee a').attributes('href')).toBe('/test');
+ });
+
+ it('renders avatar', () => {
+ expect(wrapper.find('.board-card-assignee img').exists()).toBe(true);
+ });
+ });
+
+ describe('assignee default avatar', () => {
+ beforeEach(done => {
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ assignees: [
+ new ListAssignee(
+ {
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ },
+ 'default_avatar',
+ ),
+ ],
+ },
+ });
+
+ wrapper.vm.$nextTick(done);
+ });
+
+ it('displays defaults avatar if users avatar is null', () => {
+ expect(wrapper.find('.board-card-assignee img').exists()).toBe(true);
+ expect(wrapper.find('.board-card-assignee img').attributes('src')).toBe(
+ 'default_avatar?width=24',
+ );
+ });
+ });
+ });
+
+ describe('multiple assignees', () => {
+ beforeEach(done => {
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ assignees: [
+ new ListAssignee({
+ id: 2,
+ name: 'user2',
+ username: 'user2',
+ avatar: 'test_image',
+ }),
+ new ListAssignee({
+ id: 3,
+ name: 'user3',
+ username: 'user3',
+ avatar: 'test_image',
+ }),
+ new ListAssignee({
+ id: 4,
+ name: 'user4',
+ username: 'user4',
+ avatar: 'test_image',
+ }),
+ ],
+ },
+ });
+
+ wrapper.vm.$nextTick(done);
+ });
+
+ it('renders all three assignees', () => {
+ expect(wrapper.findAll('.board-card-assignee .avatar').length).toEqual(3);
+ });
+
+ describe('more than three assignees', () => {
+ beforeEach(done => {
+ const { assignees } = wrapper.props('issue');
+ assignees.push(
+ new ListAssignee({
+ id: 5,
+ name: 'user5',
+ username: 'user5',
+ avatar: 'test_image',
+ }),
+ );
+
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ assignees,
+ },
+ });
+ wrapper.vm.$nextTick(done);
+ });
+
+ it('renders more avatar counter', () => {
+ expect(
+ wrapper
+ .find('.board-card-assignee .avatar-counter')
+ .text()
+ .trim(),
+ ).toEqual('+2');
+ });
+
+ it('renders two assignees', () => {
+ expect(wrapper.findAll('.board-card-assignee .avatar').length).toEqual(2);
+ });
+
+ it('renders 99+ avatar counter', done => {
+ const assignees = [
+ ...wrapper.props('issue').assignees,
+ ..._.range(5, 103).map(
+ i =>
+ new ListAssignee({
+ id: i,
+ name: 'name',
+ username: 'username',
+ avatar: 'test_image',
+ }),
+ ),
+ ];
+ wrapper.setProps({
+ issue: {
+ ...wrapper.props('issue'),
+ assignees,
+ },
+ });
+
+ wrapper.vm.$nextTick(() => {
+ expect(
+ wrapper
+ .find('.board-card-assignee .avatar-counter')
+ .text()
+ .trim(),
+ ).toEqual('99+');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('labels', () => {
+ beforeEach(done => {
+ issue.addLabel(label1);
+ wrapper.setProps({ issue: { ...issue } });
+
+ wrapper.vm.$nextTick(done);
+ });
+
+ it('does not render list label but renders all other labels', () => {
+ expect(wrapper.findAll('.badge').length).toBe(1);
+ });
+
+ it('renders label', () => {
+ const nodes = wrapper
+ .findAll('.badge')
+ .wrappers.map(label => label.attributes('data-original-title'));
+
+ expect(nodes.includes(label1.description)).toBe(true);
+ });
+
+ it('sets label description as title', () => {
+ expect(wrapper.find('.badge').attributes('data-original-title')).toContain(
+ label1.description,
+ );
+ });
+
+ it('sets background color of button', () => {
+ const nodes = wrapper
+ .findAll('.badge')
+ .wrappers.map(label => label.element.style.backgroundColor);
+
+ expect(nodes.includes(label1.color)).toBe(true);
+ });
+
+ it('does not render label if label does not have an ID', done => {
+ issue.addLabel(
+ new ListLabel({
+ title: 'closed',
+ }),
+ );
+ wrapper.setProps({ issue: { ...issue } });
+ wrapper.vm
+ .$nextTick()
+ .then(() => {
+ expect(wrapper.findAll('.badge').length).toBe(1);
+ expect(wrapper.text()).not.toContain('closed');
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/frontend/jobs/components/log/log_spec.js b/spec/frontend/jobs/components/log/log_spec.js
index cc334009982..7c834542a9a 100644
--- a/spec/frontend/jobs/components/log/log_spec.js
+++ b/spec/frontend/jobs/components/log/log_spec.js
@@ -60,8 +60,8 @@ describe('Job Log', () => {
expect(wrapper.find('.collapsible-line').attributes('role')).toBe('button');
});
- it('renders an icon with the closed state', () => {
- expect(wrapper.find('.collapsible-line svg').classes()).toContain('ic-angle-right');
+ it('renders an icon with the open state', () => {
+ expect(wrapper.find('.collapsible-line svg').classes()).toContain('ic-angle-down');
});
describe('on click header section', () => {
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
index 43dacfe622c..8819f39dee0 100644
--- a/spec/frontend/jobs/store/utils_spec.js
+++ b/spec/frontend/jobs/store/utils_spec.js
@@ -26,7 +26,7 @@ describe('Jobs Store Utils', () => {
const parsedHeaderLine = parseHeaderLine(headerLine, 2);
expect(parsedHeaderLine).toEqual({
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
...headerLine,
@@ -57,7 +57,7 @@ describe('Jobs Store Utils', () => {
it('adds the section duration to the correct header', () => {
const parsed = [
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
section: 'prepare-script',
@@ -66,7 +66,7 @@ describe('Jobs Store Utils', () => {
lines: [],
},
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
section: 'foo-bar',
@@ -85,7 +85,7 @@ describe('Jobs Store Utils', () => {
it('does not add the section duration when the headers do not match', () => {
const parsed = [
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
section: 'bar-foo',
@@ -94,7 +94,7 @@ describe('Jobs Store Utils', () => {
lines: [],
},
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
section: 'foo-bar',
@@ -183,7 +183,7 @@ describe('Jobs Store Utils', () => {
describe('collpasible section', () => {
it('adds a `isClosed` property', () => {
- expect(result[1].isClosed).toEqual(true);
+ expect(result[1].isClosed).toEqual(false);
});
it('adds a `isHeader` property', () => {
@@ -213,7 +213,7 @@ describe('Jobs Store Utils', () => {
const existingLog = [
{
isHeader: true,
- isClosed: true,
+ isClosed: false,
line: { content: [{ text: 'bar' }], offset: 10, lineNumber: 1 },
},
];
@@ -263,7 +263,7 @@ describe('Jobs Store Utils', () => {
const existingLog = [
{
isHeader: true,
- isClosed: true,
+ isClosed: false,
lines: [{ offset: 101, content: [{ text: 'foobar' }], lineNumber: 2 }],
line: {
offset: 10,
@@ -435,7 +435,7 @@ describe('Jobs Store Utils', () => {
expect(result).toEqual([
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
offset: 1,
@@ -461,7 +461,7 @@ describe('Jobs Store Utils', () => {
expect(result).toEqual([
{
- isClosed: true,
+ isClosed: false,
isHeader: true,
line: {
offset: 1,
diff --git a/spec/javascripts/boards/components/issue_time_estimate_spec.js b/spec/javascripts/boards/components/issue_time_estimate_spec.js
deleted file mode 100644
index de48e3f6091..00000000000
--- a/spec/javascripts/boards/components/issue_time_estimate_spec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import Vue from 'vue';
-import IssueTimeEstimate from '~/boards/components/issue_time_estimate.vue';
-import boardsStore from '~/boards/stores/boards_store';
-import mountComponent from '../../helpers/vue_mount_component_helper';
-
-describe('Issue Time Estimate component', () => {
- let vm;
-
- beforeEach(() => {
- boardsStore.create();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('when limitToHours is false', () => {
- beforeEach(() => {
- boardsStore.timeTracking.limitToHours = false;
-
- const Component = Vue.extend(IssueTimeEstimate);
- vm = mountComponent(Component, {
- estimate: 374460,
- });
- });
-
- it('renders the correct time estimate', () => {
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual('2w 3d 1m');
- });
-
- it('renders expanded time estimate in tooltip', () => {
- expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain(
- '2 weeks 3 days 1 minute',
- );
- });
-
- it('prevents tooltip xss', done => {
- const alertSpy = spyOn(window, 'alert');
- vm.estimate = 'Foo <script>alert("XSS")</script>';
-
- vm.$nextTick(() => {
- expect(alertSpy).not.toHaveBeenCalled();
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual('0m');
- expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain('0m');
- done();
- });
- });
- });
-
- describe('when limitToHours is true', () => {
- beforeEach(() => {
- boardsStore.timeTracking.limitToHours = true;
-
- const Component = Vue.extend(IssueTimeEstimate);
- vm = mountComponent(Component, {
- estimate: 374460,
- });
- });
-
- it('renders the correct time estimate', () => {
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual('104h 1m');
- });
-
- it('renders expanded time estimate in tooltip', () => {
- expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain(
- '104 hours 1 minute',
- );
- });
- });
-});
diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js
deleted file mode 100644
index df2b04cd6df..00000000000
--- a/spec/javascripts/boards/issue_card_spec.js
+++ /dev/null
@@ -1,294 +0,0 @@
-/* global ListAssignee */
-/* global ListLabel */
-/* global ListIssue */
-
-import Vue from 'vue';
-
-import '~/boards/models/label';
-import '~/boards/models/assignee';
-import '~/boards/models/issue';
-import '~/boards/models/list';
-import IssueCardInner from '~/boards/components/issue_card_inner.vue';
-import { listObj } from './mock_data';
-import store from '~/boards/stores';
-
-describe('Issue card component', () => {
- const user = new ListAssignee({
- id: 1,
- name: 'testing 123',
- username: 'test',
- avatar: 'test_image',
- });
- const label1 = new ListLabel({
- id: 3,
- title: 'testing 123',
- color: 'blue',
- text_color: 'white',
- description: 'test',
- });
- let component;
- let issue;
- let list;
-
- beforeEach(() => {
- setFixtures('<div class="test-container"></div>');
-
- list = {
- ...listObj,
- type: 'label',
- };
- issue = new ListIssue({
- title: 'Testing',
- id: 1,
- iid: 1,
- confidential: false,
- labels: [list.label],
- assignees: [],
- reference_path: '#1',
- real_path: '/test/1',
- weight: 1,
- });
-
- component = new Vue({
- el: document.querySelector('.test-container'),
- store,
- components: {
- 'issue-card': IssueCardInner,
- },
- data() {
- return {
- list,
- issue,
- issueLinkBase: '/test',
- rootPath: '/',
- };
- },
- template: `
- <issue-card
- :issue="issue"
- :list="list"
- :issue-link-base="issueLinkBase"
- :root-path="rootPath"></issue-card>
- `,
- });
- });
-
- it('renders issue title', () => {
- expect(component.$el.querySelector('.board-card-title').textContent).toContain(issue.title);
- });
-
- it('includes issue base in link', () => {
- expect(component.$el.querySelector('.board-card-title a').getAttribute('href')).toContain(
- '/test',
- );
- });
-
- it('includes issue title on link', () => {
- expect(component.$el.querySelector('.board-card-title a').getAttribute('title')).toBe(
- issue.title,
- );
- });
-
- it('does not render confidential icon', () => {
- expect(component.$el.querySelector('.fa-eye-flash')).toBeNull();
- });
-
- it('renders confidential icon', done => {
- component.issue.confidential = true;
-
- Vue.nextTick(() => {
- expect(component.$el.querySelector('.confidential-icon')).not.toBeNull();
- done();
- });
- });
-
- it('renders issue ID with #', () => {
- expect(component.$el.querySelector('.board-card-number').textContent).toContain(`#${issue.id}`);
- });
-
- describe('assignee', () => {
- it('does not render assignee', () => {
- expect(component.$el.querySelector('.board-card-assignee .avatar')).toBeNull();
- });
-
- describe('exists', () => {
- beforeEach(done => {
- component.issue.assignees = [user];
-
- Vue.nextTick(() => done());
- });
-
- it('renders assignee', () => {
- expect(component.$el.querySelector('.board-card-assignee .avatar')).not.toBeNull();
- });
-
- it('sets title', () => {
- expect(component.$el.querySelector('.js-assignee-tooltip').textContent).toContain(
- `${user.name}`,
- );
- });
-
- it('sets users path', () => {
- expect(component.$el.querySelector('.board-card-assignee a').getAttribute('href')).toBe(
- '/test',
- );
- });
-
- it('renders avatar', () => {
- expect(component.$el.querySelector('.board-card-assignee img')).not.toBeNull();
- });
- });
-
- describe('assignee default avatar', () => {
- beforeEach(done => {
- component.issue.assignees = [
- new ListAssignee(
- {
- id: 1,
- name: 'testing 123',
- username: 'test',
- },
- 'default_avatar',
- ),
- ];
-
- Vue.nextTick(done);
- });
-
- it('displays defaults avatar if users avatar is null', () => {
- expect(component.$el.querySelector('.board-card-assignee img')).not.toBeNull();
- expect(component.$el.querySelector('.board-card-assignee img').getAttribute('src')).toBe(
- 'default_avatar?width=24',
- );
- });
- });
- });
-
- describe('multiple assignees', () => {
- beforeEach(done => {
- component.issue.assignees = [
- new ListAssignee({
- id: 2,
- name: 'user2',
- username: 'user2',
- avatar: 'test_image',
- }),
- new ListAssignee({
- id: 3,
- name: 'user3',
- username: 'user3',
- avatar: 'test_image',
- }),
- new ListAssignee({
- id: 4,
- name: 'user4',
- username: 'user4',
- avatar: 'test_image',
- }),
- ];
-
- Vue.nextTick(() => done());
- });
-
- it('renders all three assignees', () => {
- expect(component.$el.querySelectorAll('.board-card-assignee .avatar').length).toEqual(3);
- });
-
- describe('more than three assignees', () => {
- beforeEach(done => {
- component.issue.assignees.push(
- new ListAssignee({
- id: 5,
- name: 'user5',
- username: 'user5',
- avatar: 'test_image',
- }),
- );
-
- Vue.nextTick(() => done());
- });
-
- it('renders more avatar counter', () => {
- expect(
- component.$el.querySelector('.board-card-assignee .avatar-counter').innerText.trim(),
- ).toEqual('+2');
- });
-
- it('renders two assignees', () => {
- expect(component.$el.querySelectorAll('.board-card-assignee .avatar').length).toEqual(2);
- });
-
- it('renders 99+ avatar counter', done => {
- for (let i = 5; i < 104; i += 1) {
- const u = new ListAssignee({
- id: i,
- name: 'name',
- username: 'username',
- avatar: 'test_image',
- });
- component.issue.assignees.push(u);
- }
-
- Vue.nextTick(() => {
- expect(
- component.$el.querySelector('.board-card-assignee .avatar-counter').innerText.trim(),
- ).toEqual('99+');
- done();
- });
- });
- });
- });
-
- describe('labels', () => {
- beforeEach(done => {
- component.issue.addLabel(label1);
-
- Vue.nextTick(() => done());
- });
-
- it('does not render list label but renders all other labels', () => {
- expect(component.$el.querySelectorAll('.badge').length).toBe(1);
- });
-
- it('renders label', () => {
- const nodes = [];
- component.$el.querySelectorAll('.badge').forEach(label => {
- nodes.push(label.getAttribute('data-original-title'));
- });
-
- expect(nodes.includes(label1.description)).toBe(true);
- });
-
- it('sets label description as title', () => {
- expect(component.$el.querySelector('.badge').getAttribute('data-original-title')).toContain(
- label1.description,
- );
- });
-
- it('sets background color of button', () => {
- const nodes = [];
- component.$el.querySelectorAll('.badge').forEach(label => {
- nodes.push(label.style.backgroundColor);
- });
-
- expect(nodes.includes(label1.color)).toBe(true);
- });
-
- it('does not render label if label does not have an ID', done => {
- component.issue.addLabel(
- new ListLabel({
- title: 'closed',
- }),
- );
-
- Vue.nextTick()
- .then(() => {
- expect(component.$el.querySelectorAll('.badge').length).toBe(1);
- expect(component.$el.textContent).not.toContain('closed');
-
- done();
- })
- .catch(done.fail);
- });
- });
-});