Commit 184f60a0 authored by Filipa Lacerda's avatar Filipa Lacerda

Moves pagination to shared folder

Document and remove unused code

Declare components in a consistent way;
Use " instead of ' to improve consistency;
Update documentation;
Fix commit author verification to match the use cases;

Adds tests for the added components

Fix paths in pagination spec

Adds tests to pipelines table used in merge requests and commits

Use same resource interceptor

Fix eslint error
parent 2c2da2c0
......@@ -3,10 +3,6 @@
//= require vue
//= require_tree .
//= require vue
//= require vue-resource
//= require vue_shared/vue_resource_interceptor
//= require vue_shared/components/pipelines_table
/**
* Commits View > Pipelines Tab > Pipelines Table.
......@@ -14,13 +10,6 @@
*
* Renders Pipelines table in pipelines tab in the commits show view.
* Renders Pipelines table in pipelines tab in the merge request show view.
*
* Uses `pipelines-table-component` to render Pipelines table with an API call.
* Endpoint is provided in HTML and passed as scope.
* We need a store to make the request and store the received environemnts.
*
* Necessary SVG in the table are provided as props. This should be refactored
* as soon as we have Webpack and can load them directly into JS files.
*/
$(() => {
......@@ -28,94 +17,11 @@ $(() => {
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
if (gl.commits.PipelinesTableView) {
gl.commits.PipelinesTableView.$destroy(true);
if (gl.commits.PipelinesTableBundle) {
gl.commits.PipelinesTableBundle.$destroy(true);
}
gl.commits.pipelines.PipelinesTableView = new Vue({
gl.commits.pipelines.PipelinesTableBundle = new gl.commits.pipelines.PipelinesTableView({
el: document.querySelector('#commit-pipeline-table-view'),
components: {
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
},
/**
* Accesses the DOM to provide the needed data.
* Returns the necessary props to render `pipelines-table-component` component.
*
* @return {Object} Props for `pipelines-table-component`
*/
data() {
const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset;
const svgsData = document.querySelector('.pipeline-svgs').dataset;
const store = gl.commits.pipelines.PipelinesStore.create();
// Transform svgs DOMStringMap to a plain Object.
const svgsObject = Object.keys(svgsData).reduce((acc, element) => {
acc[element] = svgsData[element];
return acc;
}, {});
return {
endpoint: pipelinesTableData.endpoint,
svgs: svgsObject,
store,
state: store.state,
isLoading: false,
error: false,
};
},
/**
* When the component is created the service to fetch the data will be
* initialized with the correct endpoint.
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
created() {
gl.pipelines.pipelinesService = new PipelinesService(this.endpoint);
this.isLoading = true;
return gl.pipelines.pipelinesService.all()
.then(response => response.json())
.then((json) => {
this.store.store(json);
this.isLoading = false;
this.error = false;
}).catch(() => {
this.error = true;
this.isLoading = false;
new Flash('An error occurred while fetching the pipelines.', 'alert');
});
},
template: `
<div>
<div class="pipelines realtime-loading" v-if='isLoading'>
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && !error && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
You don't have any pipelines.
</h2>
</div>
<div
class="table-holder pipelines"
v-if='!isLoading && state.pipelines.length > 0'>
<pipelines-table-component
:pipelines='state.pipelines'
:svgs='svgs'>
</pipelines-table-component>
</div>
</div>
`,
});
});
......@@ -32,3 +32,8 @@ class PipelinesService {
return this.pipelines.get();
}
}
window.gl = window.gl || {};
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
gl.commits.pipelines.PipelinesService = PipelinesService;
/* eslint-disable no-new, no-param-reassign */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */
//= require vue
//= require vue-resource
//= require vue_shared/vue_resource_interceptor
//= require vue_shared/components/pipelines_table
/**
*
* Uses `pipelines-table-component` to render Pipelines table with an API call.
* Endpoint is provided in HTML and passed as `endpoint`.
* We need a store to store the received environemnts.
* We need a service to communicate with the server.
*
* Necessary SVG in the table are provided as props. This should be refactored
* as soon as we have Webpack and can load them directly into JS files.
*/
(() => {
window.gl = window.gl || {};
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
gl.commits.pipelines.PipelinesTableView = Vue.component('pipelines-table', {
components: {
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
},
/**
* Accesses the DOM to provide the needed data.
* Returns the necessary props to render `pipelines-table-component` component.
*
* @return {Object}
*/
data() {
const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset;
const svgsData = document.querySelector('.pipeline-svgs').dataset;
const store = gl.commits.pipelines.PipelinesStore.create();
// Transform svgs DOMStringMap to a plain Object.
const svgsObject = Object.keys(svgsData).reduce((acc, element) => {
acc[element] = svgsData[element];
return acc;
}, {});
return {
endpoint: pipelinesTableData.endpoint,
svgs: svgsObject,
store,
state: store.state,
isLoading: false,
};
},
/**
* When the component is created the service to fetch the data will be
* initialized with the correct endpoint.
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
created() {
gl.pipelines.pipelinesService = new PipelinesService(this.endpoint);
this.isLoading = true;
return gl.pipelines.pipelinesService.all()
.then(response => response.json())
.then((json) => {
this.store.store(json);
this.isLoading = false;
}).catch(() => {
this.isLoading = false;
new Flash('An error occurred while fetching the pipelines.', 'alert');
});
},
template: `
<div>
<div class="pipelines realtime-loading" v-if="isLoading">
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<div class="table-holder pipelines"
v-if="!isLoading && state.pipelines.length > 0">
<pipelines-table-component
:pipelines="state.pipelines"
:svgs="svgs">
</pipelines-table-component>
</div>
</div>
`,
});
})();
//= require vue
//= require_tree ./stores/
//= require ./components/environment
//= require ./vue_resource_interceptor
//= require vue_shared/vue_resource_interceptor
$(() => {
window.gl = window.gl || {};
......
/* global Vue */
Vue.http.interceptors.push((request, next) => {
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
next((response) => {
if (typeof response.data === 'string') {
response.data = JSON.parse(response.data); // eslint-disable-line
}
Vue.activeResources--; // eslint-disable-line
});
});
/* global Vue, Turbolinks, gl */
/* eslint-disable no-param-reassign */
//= require vue_pagination/index
//= require vue_shared/components/table_pagination
//= require ./store.js.es6
//= require vue_shared/components/pipelines_table
......@@ -9,7 +9,7 @@
gl.VuePipelines = Vue.extend({
components: {
glPagination: gl.VueGlPagination,
'gl-pagination': gl.VueGlPagination,
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
},
......
/* global Vue, gl */
/* eslint-disable no-param-reassign */
//= require lib/utils/datetime_utility
((gl) => {
gl.VueTimeAgo = Vue.extend({
data() {
......
......@@ -4,10 +4,9 @@
//= require ./pipelines_table_row
/**
* Pipelines Table Component
*
* Given an array of pipelines, renders a table.
* Pipelines Table Component.
*
* Given an array of objects, renders a table.
*/
(() => {
......@@ -20,11 +19,11 @@
pipelines: {
type: Array,
required: true,
default: [],
default: () => ([]),
},
/**
* Remove this. Find a better way to do this. don't want to provide this 3 times.
* TODO: Remove this when we have webpack.
*/
svgs: {
type: Object,
......@@ -41,19 +40,18 @@
<table class="table ci-table">
<thead>
<tr>
<th class="pipeline-status">Status</th>
<th class="pipeline-info">Pipeline</th>
<th class="pipeline-commit">Commit</th>
<th class="pipeline-stages">Stages</th>
<th class="pipeline-date"></th>
<th class="pipeline-actions hidden-xs"></th>
<th class="js-pipeline-status pipeline-status">Status</th>
<th class="js-pipeline-info pipeline-info">Pipeline</th>
<th class="js-pipeline-commit pipeline-commit">Commit</th>
<th class="js-pipeline-stages pipeline-stages">Stages</th>
<th class="js-pipeline-date pipeline-date"></th>
<th class="js-pipeline-actions pipeline-actions hidden-xs"></th>
</tr>
</thead>
<tbody>
<template v-for="model in pipelines"
v-bind:model="model">
<tr
is="pipelines-table-row-component"
<tr is="pipelines-table-row-component"
:pipeline="model"
:svgs="svgs"></tr>
</template>
......
......@@ -7,6 +7,12 @@
//= require vue_shared/components/commit
//= require vue_pipelines_index/pipeline_actions
//= require vue_pipelines_index/time_ago
/**
* Pipeline table row.
*
* Given the received object renders a table row in the pipelines' table.
*/
(() => {
window.gl = window.gl || {};
gl.pipelines = gl.pipelines || {};
......@@ -21,7 +27,7 @@
},
/**
* Remove this. Find a better way to do this. don't want to provide this 3 times.
* TODO: Remove this when we have webpack;
*/
svgs: {
type: Object,
......@@ -32,12 +38,10 @@
components: {
'commit-component': gl.CommitComponent,
runningPipeline: gl.VueRunningPipeline,
pipelineActions: gl.VuePipelineActions,
'vue-stage': gl.VueStage,
pipelineUrl: gl.VuePipelineUrl,
pipelineHead: gl.VuePipelineHead,
statusScope: gl.VueStatusScope,
'pipeline-actions': gl.VuePipelineActions,
'dropdown-stage': gl.VueStage,
'pipeline-url': gl.VuePipelineUrl,
'status-scope': gl.VueStatusScope,
'time-ago': gl.VueTimeAgo,
},
......@@ -46,48 +50,48 @@
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* TODO: Document this logic, need to ask @grzesiek and @selfup
* This field needs a lot of verification, because of different possible cases:
*
* 1. person who is an author of a commit might be a GitLab user
* 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
* 3. If GitLab user does not have avatar he/she might have a Gravatar
* 4. If committer is not a GitLab User he/she can have a Gravatar
* 5. We do not have consistent API object in this case
* 6. We should improve API and the code
*
* @returns {Object|Undefined}
*/
commitAuthor() {
if (!this.pipeline.commit) {
return { avatar_url: '', web_url: '', username: '' };
}
let commitAuthorInformation;
// 1. person who is an author of a commit might be a GitLab user
if (this.pipeline &&
this.pipeline.commit &&
this.pipeline.commit.author) {
return this.pipeline.commit.author;
// 2. if person who is an author of a commit is a GitLab user
// he/she can have a GitLab avatar
if (this.pipeline.commit.author.avatar_url) {
commitAuthorInformation = this.pipeline.commit.author;
// 3. If GitLab user does not have avatar he/she might have a Gravatar
} else if (this.pipeline.commit.author_gravatar_url) {
commitAuthorInformation = Object.assign({}, this.pipeline.commit.author, {
avatar_url: this.pipeline.commit.author_gravatar_url,
});
}
}
// 4. If committer is not a GitLab User he/she can have a Gravatar
if (this.pipeline &&
this.pipeline.commit &&
this.pipeline.commit.author_gravatar_url &&
this.pipeline.commit.author_name &&
this.pipeline.commit.author_email) {
return {
this.pipeline.commit) {
commitAuthorInformation = {
avatar_url: this.pipeline.commit.author_gravatar_url,
web_url: `mailto:${this.pipeline.commit.author_email}`,
username: this.pipeline.commit.author_name,
};
}
return undefined;
},
/**
* Figure this out!
* Needed to render the commit component column.
*/
author(pipeline) {
if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' };
if (pipeline.commit.author) return pipeline.commit.author;
return {
avatar_url: pipeline.commit.author_gravatar_url,
web_url: `mailto:${pipeline.commit.author_email}`,
username: pipeline.commit.author_name,
};
return commitAuthorInformation;
},
/**
......@@ -108,6 +112,9 @@
* If provided, returns the commit ref.
* Needed to render the commit component column.
*
* Matched `url` prop sent in the API to `path` prop needed
* in the commit component.
*
* @returns {Object|Undefined}
*/
commitRef() {
......@@ -169,6 +176,17 @@
},
methods: {
/**
* FIXME: This should not be in this component but in the components that
* need this function.
*
* Used to render SVGs in the following components:
* - status-scope
* - dropdown-stage
*
* @param {String} string
* @return {String}
*/
match(string) {
return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase());
},
......@@ -177,12 +195,12 @@
template: `
<tr class="commit">
<status-scope
:pipeline='pipeline'
:svgs='svgs'
:pipeline="pipeline"
:svgs="svgs"
:match="match">
</status-scope>
<pipeline-url :pipeline='pipeline'></pipeline-url>
<pipeline-url :pipeline="pipeline"></pipeline-url>
<td>
<commit-component
......@@ -197,14 +215,20 @@
</td>
<td class="stage-cell">
<div class="stage-container dropdown js-mini-pipeline-graph" v-for='stage in pipeline.details.stages'>
<vue-stage :stage='stage' :svgs='svgs' :match='match'></vue-stage>
<div class="stage-container dropdown js-mini-pipeline-graph"
v-if="pipeline.details.stages.length > 0"
v-for="stage in pipeline.details.stages">
<dropdown-stage
:stage="stage"
:svgs="svgs"
:match="match">
</dropdown-stage>
</div>
</td>
<time-ago :pipeline='pipeline' :svgs='svgs'></time-ago>
<time-ago :pipeline="pipeline" :svgs="svgs"></time-ago>
<pipeline-actions :pipeline='pipeline' :svgs='svgs'></pipeline-actions>
<pipeline-actions :pipeline="pipeline" :svgs="svgs"></pipeline-actions>
</tr>
`,
});
......
/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars */
/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars,
no-param-reassign, no-plusplus */
/* global Vue */
Vue.http.interceptors.push((request, next) => {
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
next(function (response) {
Vue.activeResources -= 1;
next((response) => {
if (typeof response.data === 'string') {
response.data = JSON.parse(response.data);
}
Vue.activeResources--;
});
});
......@@ -37,7 +37,6 @@ class Projects::CommitController < Projects::ApplicationController
format.json do
render json: PipelineSerializer
.new(project: @project, user: @current_user)
.with_pagination(request, response)
.represent(@pipelines)
end
end
......
......@@ -218,7 +218,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
format.json do
render json: PipelineSerializer
.new(project: @project, user: @current_user)
.with_pagination(request, response)
.represent(@pipelines)
end
end
......
......@@ -44,9 +44,9 @@
= render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane
-# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane
//TODO: This needs to make a new request every time is opened!
= render "projects/merge_requests/show/pipelines", endpoint: link_to url_for(params)
- if @pipelines.any?
#pipelines.pipelines.tab-pane
= render "projects/merge_requests/show/pipelines", endpoint: link_to url_for(params)
.mr-loading-status
= spinner
......
......@@ -94,7 +94,6 @@
#commits.commits.tab-pane
-# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane
//TODO: This needs to make a new request every time is opened!
= render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
#diffs.diffs.tab-pane
-# This tab is always loaded via AJAX
......
/* eslint-disable no-unused-vars */
const pipeline = {
id: 73,
user: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
web_url: 'http://localhost:3000/root',
},
path: '/root/review-app/pipelines/73',
details: {
status: {
icon: 'icon_status_failed',
text: 'failed',
label: 'failed',
group: 'failed',
has_details: true,
details_path: '/root/review-app/pipelines/73',
},
duration: null,
finished_at: '2017-01-25T00:00:17.130Z',
stages: [{
name: 'build',
title: 'build: failed',
status: {
icon: 'icon_status_failed',
text: 'failed',
label: 'failed',
group: 'failed',
has_details: true,
details_path: '/root/review-app/pipelines/73#build',
},
path: '/root/review-app/pipelines/73#build',
dropdown_path: '/root/review-app/pipelines/73/stage.json?stage=build',
}],
artifacts: [],
manual_actions: [
{
name: 'stop_review',
path: '/root/review-app/builds/1463/play',
},
{
name: 'name',
path: '/root/review-app/builds/1490/play',
},
],
},
flags: {
latest: true,
triggered: false,
stuck: false,
yaml_errors: false,
retryable: true,
cancelable: false,
},
ref:
{
name: 'master',
path: '/root/review-app/tree/master',
tag: false,
branch: true,
},
commit: {
id: 'fbd79f04fa98717641deaaeb092a4d417237c2e4',
short_id: 'fbd79f04',
title: 'Update .gitlab-ci.yml',
author_name: 'Administrator',
author_email: 'admin@example.com',
created_at: '2017-01-16T12:13:57.000-05:00',
committer_name: 'Administrator',
committer_email: 'admin@example.com',
message: 'Update .gitlab-ci.yml',
author: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
web_url: 'http://localhost:3000/root',
},
author_gravatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
commit_url: 'http://localhost:3000/root/review-app/commit/fbd79f04fa98717641deaaeb092a4d417237c2e4',
commit_path: '/root/review-app/commit/fbd79f04fa98717641deaaeb092a4d417237c2e4',
},
retry_path: '/root/review-app/pipelines/73/retry',
created_at: '2017-01-16T17:13:59.800Z',
updated_at: '2017-01-25T00:00:17.132Z',
};
/* global pipeline, Vue */
//= require vue
//= require vue-resource
//= require flash
//= require commit/pipelines/pipelines_store
//= require commit/pipelines/pipelines_service
//= require commit/pipelines/pipelines_table
//= require vue_shared/vue_resource_interceptor
//= require ./mock_data
describe('Pipelines table in Commits and Merge requests', () => {
preloadFixtures('pipelines_table');
beforeEach(() => {
loadFixtures('pipelines_table');
});
describe('successfull request', () => {
describe('without pipelines', () => {
const pipelinesEmptyResponse = (request, next) => {
next(request.respondWith(JSON.stringify([]), {
status: 200,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(pipelinesEmptyResponse);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesEmptyResponse,
);
});
it('should render the empty state', (done) => {
const component = new gl.commits.pipelines.PipelinesTableView({
el: document.querySelector('#commit-pipeline-table-view'),
});
setTimeout(() => {
expect(component.$el.querySelector('.js-blank-state-title').textContent).toContain('No pipelines to show');
done();
}, 1);
});
});
describe('with pipelines', () => {
const pipelinesResponse = (request, next) => {
next(request.respondWith(JSON.stringify([pipeline]), {
status: 200,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(pipelinesResponse);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesResponse,
);
});
it('should render a table with the received pipelines', (done) => {
const component = new gl.commits.pipelines.PipelinesTableView({
el: document.querySelector('#commit-pipeline-table-view'),
});
setTimeout(() => {
expect(component.$el.querySelectorAll('table > tbody > tr').length).toEqual(1);
done();
}, 0);
});
});
});
describe('unsuccessfull request', () => {
const pipelinesErrorResponse = (request, next) => {
next(request.respondWith(JSON.stringify([]), {
status: 500,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(pipelinesErrorResponse);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesErrorResponse,
);
});
it('should render empty state', (done) => {
const component = new gl.commits.pipelines.PipelinesTableView({
el: document.querySelector('#commit-pipeline-table-view'),
});
setTimeout(() => {
expect(component.$el.querySelector('.js-blank-state-title').textContent).toContain('No pipelines to show');
done();
}, 0);
});
});
});
//= require vue
//= require commit/pipelines/pipelines_store
describe('Store', () => {
const store = gl.commits.pipelines.PipelinesStore;
beforeEach(() => {
store.create();
});
it('should start with a blank state', () => {
expect(store.state.pipelines.length).toBe(0);
});
it('should store an array of pipelines', () => {
const pipelines = [
{
id: '1',
name: 'pipeline',
},
{
id: '2',
name: 'pipeline_2',
},
];
store.store(pipelines);
expect(store.state.pipelines.length).toBe(pipelines.length);
});
});
#commit-pipeline-table-view{ data: { endpoint: "endpoint" } }
.pipeline-svgs{ data: { "commit_icon_svg": "svg"} }
/* global pipeline */
//= require vue
//= require vue_shared/components/pipelines_table_row
//= require commit/pipelines/mock_data
describe('Pipelines Table Row', () => {
let component;
preloadFixtures('static/environments/element.html.raw');
beforeEach(() => {
loadFixtures('static/environments/element.html.raw');
component = new gl.pipelines.PipelinesTableRowComponent({
el: document.querySelector('.test-dom-element'),
propsData: {
pipeline,
svgs: {},
},
});
});
it('should render a table row', () => {
expect(component.$el).toEqual('TR');
});
describe('status column', () => {
it('should render a pipeline link', () => {
expect(
component.$el.querySelector('td.commit-link a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render status text', () => {
expect(
component.$el.querySelector('td.commit-link a').textContent,
).toContain(pipeline.details.status.text);
});
});
describe('information column', () => {
it('should render a pipeline link', () => {
expect(
component.$el.querySelector('td:nth-child(2) a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render pipeline ID', () => {
expect(
component.$el.querySelector('td:nth-child(2) a > span').textContent,
).toEqual(`#${pipeline.id}`);
});
describe('when a user is provided', () => {
it('should render user information', () => {
expect(
component.$el.querySelector('td:nth-child(2) a:nth-child(3)').getAttribute('href'),
).toEqual(pipeline.user.web_url);
expect(
component.$el.querySelector('td:nth-child(2) img').getAttribute('title'),
).toEqual(pipeline.user.name);
});
});
});
describe('commit column', () => {
it('should render link to commit', () => {
expect(
component.$el.querySelector('td:nth-child(3) .commit-id').getAttribute('href'),
).toEqual(pipeline.commit.commit_path);
});
});
describe('stages column', () => {
it('should render an icon for each stage', () => {
expect(
component.$el.querySelectorAll('td:nth-child(4) .js-builds-dropdown-button').length,
).toEqual(pipeline.details.stages.length);
});
});
describe('actions column', () => {
it('should render the provided actions', () => {
expect(
component.$el.querySelectorAll('td:nth-child(6) ul li').length,
).toEqual(pipeline.details.manual_actions.length);
});
});
});
/* global pipeline */
//= require vue
//= require vue_shared/components/pipelines_table
//= require commit/pipelines/mock_data
//= require lib/utils/datetime_utility
describe('Pipelines Table', () => {
preloadFixtures('static/environments/element.html.raw');
beforeEach(() => {
loadFixtures('static/environments/element.html.raw');
});
describe('table', () => {
let component;
beforeEach(() => {
component = new gl.pipelines.PipelinesTableComponent({
el: document.querySelector('.test-dom-element'),
propsData: {
pipelines: [],
svgs: {},
},
});
});
it('should render a table', () => {
expect(component.$el).toEqual('TABLE');
});
it('should render table head with correct columns', () => {
expect(component.$el.querySelector('th.js-pipeline-status').textContent).toEqual('Status');
expect(component.$el.querySelector('th.js-pipeline-info').textContent).toEqual('Pipeline');
expect(component.$el.querySelector('th.js-pipeline-commit').textContent).toEqual('Commit');
expect(component.$el.querySelector('th.js-pipeline-stages').textContent).toEqual('Stages');
expect(component.$el.querySelector('th.js-pipeline-date').textContent).toEqual('');
expect(component.$el.querySelector('th.js-pipeline-actions').textContent).toEqual('');
});
});
describe('without data', () => {
it('should render an empty table', () => {
const component = new gl.pipelines.PipelinesTableComponent({
el: document.querySelector('.test-dom-element'),
propsData: {
pipelines: [],
svgs: {},
},
});
expect(component.$el.querySelectorAll('tbody tr').length).toEqual(0);
});
});
describe('with data', () => {
it('should render rows', () => {
const component = new gl.pipelines.PipelinesTableComponent({
el: document.querySelector('.test-dom-element'),
propsData: {
pipelines: [pipeline],
svgs: {},
},
});
expect(component.$el.querySelectorAll('tbody tr').length).toEqual(1);
});
});
});
//= require vue
//= require lib/utils/common_utils
//= require vue_pagination/index
//= require vue_shared/components/table_pagination
/* global fixture, gl */
describe('Pagination component', () => {
let component;
......
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