Commit c5aacd26 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'migrate-pipelines-spec-jest' into 'master'

Migrate pipelines graph folder spec to jest

See merge request gitlab-org/gitlab!28955
parents bea8d2af 88a4f6a4
......@@ -7,6 +7,7 @@ import ActionComponent from '~/pipelines/components/graph/action_component.vue';
describe('pipeline graph action component', () => {
let wrapper;
let mock;
const findButton = () => wrapper.find('button');
beforeEach(() => {
mock = new MockAdapter(axios);
......@@ -44,15 +45,15 @@ describe('pipeline graph action component', () => {
});
it('should render an svg', () => {
expect(wrapper.find('.ci-action-icon-wrapper')).toBeDefined();
expect(wrapper.find('svg')).toBeDefined();
expect(wrapper.find('.ci-action-icon-wrapper').exists()).toBe(true);
expect(wrapper.find('svg').exists()).toBe(true);
});
describe('on click', () => {
it('emits `pipelineActionRequestComplete` after a successful request', done => {
jest.spyOn(wrapper.vm, '$emit');
wrapper.find('button').trigger('click');
findButton().trigger('click');
waitForPromises()
.then(() => {
......@@ -63,7 +64,7 @@ describe('pipeline graph action component', () => {
});
it('renders a loading icon while waiting for request', done => {
wrapper.find('button').trigger('click');
findButton().trigger('click');
wrapper.vm.$nextTick(() => {
expect(wrapper.find('.js-action-icon-loading').exists()).toBe(true);
......
import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { shallowMount } from '@vue/test-utils';
import JobGroupDropdown from '~/pipelines/components/graph/job_group_dropdown.vue';
describe('job group dropdown component', () => {
const Component = Vue.extend(JobGroupDropdown);
let vm;
const group = {
jobs: [
{
......@@ -66,20 +62,23 @@ describe('job group dropdown component', () => {
},
};
let wrapper;
const findButton = () => wrapper.find('button');
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
beforeEach(() => {
vm = mountComponent(Component, { group });
wrapper = shallowMount(JobGroupDropdown, { propsData: { group } });
});
it('renders button with group name and size', () => {
expect(vm.$el.querySelector('button').textContent).toContain(group.name);
expect(vm.$el.querySelector('button').textContent).toContain(group.size);
expect(findButton().text()).toContain(group.name);
expect(findButton().text()).toContain(group.size);
});
it('renders dropdown with jobs', () => {
expect(vm.$el.querySelectorAll('.scrollable-menu>ul>li').length).toEqual(group.jobs.length);
expect(wrapper.findAll('.scrollable-menu>ul>li').length).toBe(group.jobs.length);
});
});
......@@ -47,7 +47,7 @@ describe('pipeline graph job item', () => {
expect(link.attributes('title')).toEqual(`${mockJob.name} - ${mockJob.status.label}`);
expect(wrapper.find('.js-status-icon-success')).toBeDefined();
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
expect(trimText(wrapper.find('.ci-status-text').text())).toBe(mockJob.name);
......@@ -73,7 +73,7 @@ describe('pipeline graph job item', () => {
},
});
expect(wrapper.find('.js-status-icon-success')).toBeDefined();
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
expect(wrapper.find('a').exists()).toBe(false);
expect(trimText(wrapper.find('.ci-status-text').text())).toEqual(mockJob.name);
......@@ -84,8 +84,8 @@ describe('pipeline graph job item', () => {
it('it should render the action icon', () => {
createWrapper({ job: mockJob });
expect(wrapper.find('a.ci-action-icon-container')).toBeDefined();
expect(wrapper.find('i.ci-action-icon-wrapper')).toBeDefined();
expect(wrapper.find('.ci-action-icon-container').exists()).toBe(true);
expect(wrapper.find('.ci-action-icon-wrapper').exists()).toBe(true);
});
});
......
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import ciIcon from '~/vue_shared/components/ci_icon.vue';
import jobNameComponent from '~/pipelines/components/graph/job_name_component.vue';
describe('job name component', () => {
let component;
let wrapper;
const propsData = {
name: 'foo',
status: {
icon: 'status_success',
group: 'success',
},
};
beforeEach(() => {
const JobNameComponent = Vue.extend(jobNameComponent);
component = new JobNameComponent({
propsData: {
name: 'foo',
status: {
icon: 'status_success',
},
},
}).$mount();
wrapper = mount(jobNameComponent, {
propsData,
});
});
it('should render the provided name', () => {
expect(component.$el.querySelector('.ci-status-text').textContent.trim()).toEqual('foo');
expect(
wrapper
.find('.ci-status-text')
.text()
.trim(),
).toBe(propsData.name);
});
it('should render an icon with the provided status', () => {
expect(component.$el.querySelector('.ci-status-icon-success')).toBeDefined();
expect(component.$el.querySelector('.ci-status-icon-success svg')).toBeDefined();
expect(wrapper.find(ciIcon).exists()).toBe(true);
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
});
});
import { mount } from '@vue/test-utils';
import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
import mockData from './linked_pipelines_mock_data';
const mockPipeline = mockData.triggered[0];
const validTriggeredPipelineId = mockPipeline.project.id;
const invalidTriggeredPipelineId = mockPipeline.project.id + 5;
describe('Linked pipeline', () => {
let wrapper;
const findButton = () => wrapper.find('button');
const createWrapper = propsData => {
wrapper = mount(LinkedPipelineComponent, {
......@@ -21,7 +26,7 @@ describe('Linked pipeline', () => {
describe('rendered output', () => {
const props = {
pipeline: mockPipeline,
projectId: 20,
projectId: invalidTriggeredPipelineId,
columnTitle: 'Downstream',
};
......@@ -44,14 +49,13 @@ describe('Linked pipeline', () => {
});
it('should render an svg within the status container', () => {
const pipelineStatusElement = wrapper.find('.js-linked-pipeline-status');
const pipelineStatusElement = wrapper.find(CiStatus);
expect(pipelineStatusElement.find('svg').exists()).toBe(true);
});
it('should render the pipeline status icon svg', () => {
expect(wrapper.find('.js-ci-status-icon-running').exists()).toBe(true);
expect(wrapper.find('.js-ci-status-icon-running').html()).toContain('<svg');
expect(wrapper.find('.ci-status-icon-failed svg').exists()).toBe(true);
});
it('should have a ci-status child component', () => {
......@@ -88,7 +92,7 @@ describe('Linked pipeline', () => {
describe('parent/child', () => {
const downstreamProps = {
pipeline: mockPipeline,
projectId: 19,
projectId: validTriggeredPipelineId,
columnTitle: 'Downstream',
};
......@@ -116,7 +120,7 @@ describe('Linked pipeline', () => {
describe('when isLoading is true', () => {
const props = {
pipeline: { ...mockPipeline, isLoading: true },
projectId: 19,
projectId: invalidTriggeredPipelineId,
columnTitle: 'Downstream',
};
......@@ -132,7 +136,7 @@ describe('Linked pipeline', () => {
describe('on click', () => {
const props = {
pipeline: mockPipeline,
projectId: 19,
projectId: validTriggeredPipelineId,
columnTitle: 'Downstream',
};
......@@ -142,18 +146,18 @@ describe('Linked pipeline', () => {
it('emits `pipelineClicked` event', () => {
jest.spyOn(wrapper.vm, '$emit');
wrapper.find('button').trigger('click');
findButton().trigger('click');
expect(wrapper.emitted().pipelineClicked).toBeTruthy();
});
it('should emit `bv::hide::tooltip` to close the tooltip', () => {
jest.spyOn(wrapper.vm.$root, '$emit');
wrapper.find('button').trigger('click');
findButton().trigger('click');
expect(wrapper.vm.$root.$emit.mock.calls[0]).toEqual([
'bv::hide::tooltip',
'js-linked-pipeline-132',
'js-linked-pipeline-34993051',
]);
});
});
......
import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { shallowMount } from '@vue/test-utils';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
import LinkedPipeline from '~/pipelines/components/graph/linked_pipeline.vue';
import mockData from './linked_pipelines_mock_data';
describe('Linked Pipelines Column', () => {
const Component = Vue.extend(LinkedPipelinesColumn);
const props = {
const propsData = {
columnTitle: 'Upstream',
linkedPipelines: mockData.triggered,
graphPosition: 'right',
projectId: 19,
};
let vm;
let wrapper;
beforeEach(() => {
vm = mountComponent(Component, props);
wrapper = shallowMount(LinkedPipelinesColumn, { propsData });
});
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
it('renders the pipeline orientation', () => {
const titleElement = vm.$el.querySelector('.linked-pipelines-column-title');
const titleElement = wrapper.find('.linked-pipelines-column-title');
expect(titleElement.innerText).toContain(props.columnTitle);
});
it('has the correct number of linked pipeline child components', () => {
expect(vm.$children.length).toBe(props.linkedPipelines.length);
expect(titleElement.text()).toBe(propsData.columnTitle);
});
it('renders the correct number of linked pipelines', () => {
const linkedPipelineElements = vm.$el.querySelectorAll('.linked-pipeline');
const linkedPipelineElements = wrapper.findAll(LinkedPipeline);
expect(linkedPipelineElements.length).toBe(props.linkedPipelines.length);
expect(linkedPipelineElements.length).toBe(propsData.linkedPipelines.length);
});
it('renders cross project triangle when column is upstream', () => {
expect(vm.$el.querySelector('.cross-project-triangle')).toBeDefined();
expect(wrapper.find('.cross-project-triangle').exists()).toBe(true);
});
});
This source diff could not be displayed because it is too large. You can view the blob instead.
import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { shallowMount } from '@vue/test-utils';
import stageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
describe('stage column component', () => {
let component;
const StageColumnComponent = Vue.extend(stageColumnComponent);
const mockJob = {
id: 4250,
name: 'test',
......@@ -24,6 +21,8 @@ describe('stage column component', () => {
},
};
let wrapper;
beforeEach(() => {
const mockGroups = [];
for (let i = 0; i < 3; i += 1) {
......@@ -32,40 +31,51 @@ describe('stage column component', () => {
mockGroups.push(mockedJob);
}
component = mountComponent(StageColumnComponent, {
title: 'foo',
groups: mockGroups,
hasTriggeredBy: false,
wrapper = shallowMount(stageColumnComponent, {
propsData: {
title: 'foo',
groups: mockGroups,
hasTriggeredBy: false,
},
});
});
it('should render provided title', () => {
expect(component.$el.querySelector('.stage-name').textContent.trim()).toEqual('foo');
expect(
wrapper
.find('.stage-name')
.text()
.trim(),
).toBe('foo');
});
it('should render the provided groups', () => {
expect(component.$el.querySelectorAll('.builds-container > ul > li').length).toEqual(3);
expect(wrapper.findAll('.builds-container > ul > li').length).toBe(
wrapper.props('groups').length,
);
});
describe('jobId', () => {
it('escapes job name', () => {
component = mountComponent(StageColumnComponent, {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
wrapper = shallowMount(stageColumnComponent, {
propsData: {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
},
},
},
],
title: 'test',
hasTriggeredBy: false,
],
title: 'test',
hasTriggeredBy: false,
},
});
expect(component.$el.querySelector('.builds-container li').getAttribute('id')).toEqual(
expect(wrapper.find('.builds-container li').attributes('id')).toBe(
'ci-badge-&lt;img src=x onerror=alert(document.domain)&gt;',
);
});
......@@ -73,50 +83,54 @@ describe('stage column component', () => {
describe('with action', () => {
it('renders action button', () => {
component = mountComponent(StageColumnComponent, {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
wrapper = shallowMount(stageColumnComponent, {
propsData: {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
},
},
],
title: 'test',
hasTriggeredBy: false,
action: {
icon: 'play',
title: 'Play all',
path: 'action',
},
],
title: 'test',
hasTriggeredBy: false,
action: {
icon: 'play',
title: 'Play all',
path: 'action',
},
});
expect(component.$el.querySelector('.js-stage-action')).not.toBeNull();
expect(wrapper.find('.js-stage-action').exists()).toBe(true);
});
});
describe('without action', () => {
it('does not render action button', () => {
component = mountComponent(StageColumnComponent, {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
wrapper = shallowMount(stageColumnComponent, {
propsData: {
groups: [
{
id: 4259,
name: '<img src=x onerror=alert(document.domain)>',
status: {
icon: 'status_success',
label: 'success',
tooltip: '<img src=x onerror=alert(document.domain)>',
},
},
},
],
title: 'test',
hasTriggeredBy: false,
],
title: 'test',
hasTriggeredBy: false,
},
});
expect(component.$el.querySelector('.js-stage-action')).toBeNull();
expect(wrapper.find('.js-stage-action').exists()).toBe(false);
});
});
});
import mockData from '../../../frontend/pipelines/graph/linked_pipelines_mock_data';
export default mockData;
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