summaryrefslogtreecommitdiff
path: root/spec/javascripts
diff options
context:
space:
mode:
authorConstance Okoghenun <cokoghenun@gitlab.com>2018-02-16 19:26:01 +0100
committerConstance Okoghenun <cokoghenun@gitlab.com>2018-02-16 19:26:01 +0100
commit6b63e11db6046bfd8275f64f36b32b408b6fcab1 (patch)
tree46be703e6abdcd81f910f3a96a23972b5e8df370 /spec/javascripts
parent7282dbea094e5dffa3af29f00e183d063a3717b1 (diff)
parentdfb14e4d22aa91d9d3fbcee5c7e44ae61bf18c51 (diff)
downloadgitlab-ce-6b63e11db6046bfd8275f64f36b32b408b6fcab1.tar.gz
Merge branch 'master' of https://gitlab.com/gitlab-org/gitlab-ce into boards-bundle-refactor
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/ci_variable_list/ajax_variable_list_spec.js46
-rw-r--r--spec/javascripts/ci_variable_list/ci_variable_list_spec.js41
-rw-r--r--spec/javascripts/commits_spec.js20
-rw-r--r--spec/javascripts/importer_status_spec.js74
-rw-r--r--spec/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js (renamed from spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js)2
-rw-r--r--spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js (renamed from spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js)2
-rw-r--r--spec/javascripts/vue_shared/components/gl_modal_spec.js192
7 files changed, 344 insertions, 33 deletions
diff --git a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js
index 5b9cdceee71..ee457a9c48c 100644
--- a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js
+++ b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js
@@ -1,8 +1,10 @@
+import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import AjaxFormVariableList from '~/ci_variable_list/ajax_variable_list';
const VARIABLE_PATCH_ENDPOINT = 'http://test.host/frontend-fixtures/builds-project/variables';
+const HIDE_CLASS = 'hide';
describe('AjaxFormVariableList', () => {
preloadFixtures('projects/ci_cd_settings.html.raw');
@@ -45,16 +47,16 @@ describe('AjaxFormVariableList', () => {
const loadingIcon = saveButton.querySelector('.js-secret-variables-save-loading-icon');
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(() => {
- expect(loadingIcon.classList.contains('hide')).toEqual(false);
+ expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(false);
return [200, {}];
});
- expect(loadingIcon.classList.contains('hide')).toEqual(true);
+ expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
ajaxVariableList.onSaveClicked()
.then(() => {
- expect(loadingIcon.classList.contains('hide')).toEqual(true);
+ expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
})
.then(done)
.catch(done.fail);
@@ -78,11 +80,11 @@ describe('AjaxFormVariableList', () => {
it('hides any previous error box', (done) => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200);
- expect(errorBox.classList.contains('hide')).toEqual(true);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
ajaxVariableList.onSaveClicked()
.then(() => {
- expect(errorBox.classList.contains('hide')).toEqual(true);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
})
.then(done)
.catch(done.fail);
@@ -103,17 +105,39 @@ describe('AjaxFormVariableList', () => {
.catch(done.fail);
});
+ it('hides secret values', (done) => {
+ mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {});
+
+ const row = container.querySelector('.js-row:first-child');
+ const valueInput = row.querySelector('.js-ci-variable-input-value');
+ const valuePlaceholder = row.querySelector('.js-secret-value-placeholder');
+
+ valueInput.value = 'bar';
+ $(valueInput).trigger('input');
+
+ expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(true);
+ expect(valueInput.classList.contains(HIDE_CLASS)).toBe(false);
+
+ ajaxVariableList.onSaveClicked()
+ .then(() => {
+ expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(false);
+ expect(valueInput.classList.contains(HIDE_CLASS)).toBe(true);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
it('shows error box with validation errors', (done) => {
const validationError = 'some validation error';
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(400, [
validationError,
]);
- expect(errorBox.classList.contains('hide')).toEqual(true);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
ajaxVariableList.onSaveClicked()
.then(() => {
- expect(errorBox.classList.contains('hide')).toEqual(false);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(false);
expect(errorBox.textContent.trim().replace(/\n+\s+/m, ' ')).toEqual(`Validation failed ${validationError}`);
})
.then(done)
@@ -123,11 +147,11 @@ describe('AjaxFormVariableList', () => {
it('shows flash message when request fails', (done) => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(500);
- expect(errorBox.classList.contains('hide')).toEqual(true);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
ajaxVariableList.onSaveClicked()
.then(() => {
- expect(errorBox.classList.contains('hide')).toEqual(true);
+ expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
})
.then(done)
.catch(done.fail);
@@ -170,9 +194,9 @@ describe('AjaxFormVariableList', () => {
const valueInput = row.querySelector('.js-ci-variable-input-value');
keyInput.value = 'foo';
- keyInput.dispatchEvent(new Event('input'));
+ $(keyInput).trigger('input');
valueInput.value = 'bar';
- valueInput.dispatchEvent(new Event('input'));
+ $(valueInput).trigger('input');
expect(idInput.value).toEqual('');
diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
index 8acb346901f..cac785fd3c6 100644
--- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
+++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
@@ -1,6 +1,8 @@
import VariableList from '~/ci_variable_list/ci_variable_list';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper';
+const HIDE_CLASS = 'hide';
+
describe('VariableList', () => {
preloadFixtures('pipeline_schedules/edit.html.raw');
preloadFixtures('pipeline_schedules/edit_with_variables.html.raw');
@@ -92,14 +94,14 @@ describe('VariableList', () => {
const $inputValue = $row.find('.js-ci-variable-input-value');
const $placeholder = $row.find('.js-secret-value-placeholder');
- expect($placeholder.hasClass('hide')).toBe(false);
- expect($inputValue.hasClass('hide')).toBe(true);
+ expect($placeholder.hasClass(HIDE_CLASS)).toBe(false);
+ expect($inputValue.hasClass(HIDE_CLASS)).toBe(true);
// Reveal values
$wrapper.find('.js-secret-value-reveal-button').click();
- expect($placeholder.hasClass('hide')).toBe(true);
- expect($inputValue.hasClass('hide')).toBe(false);
+ expect($placeholder.hasClass(HIDE_CLASS)).toBe(true);
+ expect($inputValue.hasClass(HIDE_CLASS)).toBe(false);
});
});
});
@@ -179,4 +181,35 @@ describe('VariableList', () => {
expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3);
});
});
+
+ describe('hideValues', () => {
+ beforeEach(() => {
+ loadFixtures('projects/ci_cd_settings.html.raw');
+ $wrapper = $('.js-ci-variable-list-section');
+
+ variableList = new VariableList({
+ container: $wrapper,
+ formField: 'variables',
+ });
+ variableList.init();
+ });
+
+ it('should hide value input and show placeholder stars', () => {
+ const $row = $wrapper.find('.js-row');
+ const $inputValue = $row.find('.js-ci-variable-input-value');
+ const $placeholder = $row.find('.js-secret-value-placeholder');
+
+ $row.find('.js-ci-variable-input-value')
+ .val('foo')
+ .trigger('input');
+
+ expect($placeholder.hasClass(HIDE_CLASS)).toBe(true);
+ expect($inputValue.hasClass(HIDE_CLASS)).toBe(false);
+
+ variableList.hideValues();
+
+ expect($placeholder.hasClass(HIDE_CLASS)).toBe(false);
+ expect($inputValue.hasClass(HIDE_CLASS)).toBe(true);
+ });
+ });
});
diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js
index 44ec9e4eabf..1daccc8dd02 100644
--- a/spec/javascripts/commits_spec.js
+++ b/spec/javascripts/commits_spec.js
@@ -4,6 +4,8 @@ import axios from '~/lib/utils/axios_utils';
import CommitsList from '~/commits';
describe('Commits List', () => {
+ let commitsList;
+
beforeEach(() => {
setFixtures(`
<form class="commits-search-form" action="/h5bp/html5-boilerplate/commits/master">
@@ -11,6 +13,7 @@ describe('Commits List', () => {
</form>
<ol id="commits-list"></ol>
`);
+ commitsList = new CommitsList(25);
});
it('should be defined', () => {
@@ -19,7 +22,7 @@ describe('Commits List', () => {
describe('processCommits', () => {
it('should join commit headers', () => {
- CommitsList.$contentList = $(`
+ commitsList.$contentList = $(`
<div>
<li class="commit-header" data-day="2016-09-20">
<span class="day">20 Sep, 2016</span>
@@ -39,7 +42,7 @@ describe('Commits List', () => {
// The last commit header should be removed
// since the previous one has the same data-day value.
- expect(CommitsList.processCommits(data).find('li.commit-header').length).toBe(0);
+ expect(commitsList.processCommits(data).find('li.commit-header').length).toBe(0);
});
});
@@ -48,8 +51,7 @@ describe('Commits List', () => {
let mock;
beforeEach(() => {
- CommitsList.init(25);
- CommitsList.searchField.val('');
+ commitsList.searchField.val('');
spyOn(history, 'replaceState').and.stub();
mock = new MockAdapter(axios);
@@ -66,11 +68,11 @@ describe('Commits List', () => {
});
it('should save the last search string', (done) => {
- CommitsList.searchField.val('GitLab');
- CommitsList.filterResults()
+ commitsList.searchField.val('GitLab');
+ commitsList.filterResults()
.then(() => {
expect(ajaxSpy).toHaveBeenCalled();
- expect(CommitsList.lastSearch).toEqual('GitLab');
+ expect(commitsList.lastSearch).toEqual('GitLab');
done();
})
@@ -78,10 +80,10 @@ describe('Commits List', () => {
});
it('should not make ajax call if the input does not change', (done) => {
- CommitsList.filterResults()
+ commitsList.filterResults()
.then(() => {
expect(ajaxSpy).not.toHaveBeenCalled();
- expect(CommitsList.lastSearch).toEqual('');
+ expect(commitsList.lastSearch).toEqual('');
done();
})
diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js
index bb49c576e91..71a2cd51f63 100644
--- a/spec/javascripts/importer_status_spec.js
+++ b/spec/javascripts/importer_status_spec.js
@@ -3,9 +3,18 @@ import axios from '~/lib/utils/axios_utils';
import MockAdapter from 'axios-mock-adapter';
describe('Importer Status', () => {
+ let instance;
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
describe('addToImport', () => {
- let instance;
- let mock;
const importUrl = '/import_url';
beforeEach(() => {
@@ -21,11 +30,6 @@ describe('Importer Status', () => {
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
instance = new ImporterStatus('', importUrl);
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
});
it('sets table row to active after post request', (done) => {
@@ -44,4 +48,60 @@ describe('Importer Status', () => {
.catch(done.fail);
});
});
+
+ describe('autoUpdate', () => {
+ const jobsUrl = '/jobs_url';
+
+ beforeEach(() => {
+ const div = document.createElement('div');
+ div.innerHTML = `
+ <div id="project_1">
+ <div class="job-status">
+ </div>
+ </div>
+ `;
+
+ document.body.appendChild(div);
+
+ spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
+ spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
+ instance = new ImporterStatus(jobsUrl);
+ });
+
+ function setupMock(importStatus) {
+ mock.onGet(jobsUrl).reply(200, [{
+ id: 1,
+ import_status: importStatus,
+ }]);
+ }
+
+ function expectJobStatus(done, status) {
+ instance.autoUpdate()
+ .then(() => {
+ expect(document.querySelector('#project_1').innerText.trim()).toEqual(status);
+ done();
+ })
+ .catch(done.fail);
+ }
+
+ it('sets the job status to done', (done) => {
+ setupMock('finished');
+ expectJobStatus(done, 'done');
+ });
+
+ it('sets the job status to scheduled', (done) => {
+ setupMock('scheduled');
+ expectJobStatus(done, 'scheduled');
+ });
+
+ it('sets the job status to started', (done) => {
+ setupMock('started');
+ expectJobStatus(done, 'started');
+ });
+
+ it('sets the job status to custom status', (done) => {
+ setupMock('custom status');
+ expectJobStatus(done, 'custom status');
+ });
+ });
});
diff --git a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
index 040d14efed2..4655e29eed0 100644
--- a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
+++ b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
-import IntervalPatternInput from '~/pipeline_schedules/components/interval_pattern_input.vue';
+import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
Vue.use(Translate);
diff --git a/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
index ed481cb60a1..f95a7cef18a 100644
--- a/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js
+++ b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import Cookies from 'js-cookie';
-import PipelineSchedulesCallout from '~/pipeline_schedules/components/pipeline_schedules_callout.vue';
+import PipelineSchedulesCallout from '~/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue';
const PipelineSchedulesCalloutComponent = Vue.extend(PipelineSchedulesCallout);
const cookieKey = 'pipeline_schedules_callout_dismissed';
diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js
new file mode 100644
index 00000000000..d6148cb785b
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js
@@ -0,0 +1,192 @@
+import Vue from 'vue';
+import GlModal from '~/vue_shared/components/gl_modal.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+const modalComponent = Vue.extend(GlModal);
+
+describe('GlModal', () => {
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('props', () => {
+ describe('with id', () => {
+ const props = {
+ id: 'my-modal',
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, props);
+ });
+
+ it('assigns the id to the modal', () => {
+ expect(vm.$el.id).toBe(props.id);
+ });
+ });
+
+ describe('without id', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, { });
+ });
+
+ it('does not add an id attribute to the modal', () => {
+ expect(vm.$el.hasAttribute('id')).toBe(false);
+ });
+ });
+
+ describe('with headerTitleText', () => {
+ const props = {
+ headerTitleText: 'my title text',
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, props);
+ });
+
+ it('sets the modal title', () => {
+ const modalTitle = vm.$el.querySelector('.modal-title');
+ expect(modalTitle.innerHTML.trim()).toBe(props.headerTitleText);
+ });
+ });
+
+ describe('with footerPrimaryButtonVariant', () => {
+ const props = {
+ footerPrimaryButtonVariant: 'danger',
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, props);
+ });
+
+ it('sets the primary button class', () => {
+ const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type');
+ expect(primaryButton).toHaveClass(`btn-${props.footerPrimaryButtonVariant}`);
+ });
+ });
+
+ describe('with footerPrimaryButtonText', () => {
+ const props = {
+ footerPrimaryButtonText: 'my button text',
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, props);
+ });
+
+ it('sets the primary button text', () => {
+ const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type');
+ expect(primaryButton.innerHTML.trim()).toBe(props.footerPrimaryButtonText);
+ });
+ });
+ });
+
+ it('works with data-toggle="modal"', (done) => {
+ setFixtures(`
+ <button id="modal-button" data-toggle="modal" data-target="#my-modal"></button>
+ <div id="modal-container"></div>
+ `);
+
+ const modalContainer = document.getElementById('modal-container');
+ const modalButton = document.getElementById('modal-button');
+ vm = mountComponent(modalComponent, {
+ id: 'my-modal',
+ }, modalContainer);
+ $(vm.$el).on('shown.bs.modal', () => done());
+
+ modalButton.click();
+ });
+
+ describe('methods', () => {
+ const dummyEvent = 'not really an event';
+
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, { });
+ spyOn(vm, '$emit');
+ });
+
+ describe('emitCancel', () => {
+ it('emits a cancel event', () => {
+ vm.emitCancel(dummyEvent);
+
+ expect(vm.$emit).toHaveBeenCalledWith('cancel', dummyEvent);
+ });
+ });
+
+ describe('emitSubmit', () => {
+ it('emits a submit event', () => {
+ vm.emitSubmit(dummyEvent);
+
+ expect(vm.$emit).toHaveBeenCalledWith('submit', dummyEvent);
+ });
+ });
+ });
+
+ describe('slots', () => {
+ const slotContent = 'this should go into the slot';
+ const modalWithSlot = (slotName) => {
+ let template;
+ if (slotName) {
+ template = `
+ <gl-modal>
+ <template slot="${slotName}">${slotContent}</template>
+ </gl-modal>
+ `;
+ } else {
+ template = `<gl-modal>${slotContent}</gl-modal>`;
+ }
+
+ return Vue.extend({
+ components: {
+ GlModal,
+ },
+ template,
+ });
+ };
+
+ describe('default slot', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalWithSlot());
+ });
+
+ it('sets the modal body', () => {
+ const modalBody = vm.$el.querySelector('.modal-body');
+ expect(modalBody.innerHTML).toBe(slotContent);
+ });
+ });
+
+ describe('header slot', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalWithSlot('header'));
+ });
+
+ it('sets the modal header', () => {
+ const modalHeader = vm.$el.querySelector('.modal-header');
+ expect(modalHeader.innerHTML).toBe(slotContent);
+ });
+ });
+
+ describe('title slot', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalWithSlot('title'));
+ });
+
+ it('sets the modal title', () => {
+ const modalTitle = vm.$el.querySelector('.modal-title');
+ expect(modalTitle.innerHTML).toBe(slotContent);
+ });
+ });
+
+ describe('footer slot', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalWithSlot('footer'));
+ });
+
+ it('sets the modal footer', () => {
+ const modalFooter = vm.$el.querySelector('.modal-footer');
+ expect(modalFooter.innerHTML).toBe(slotContent);
+ });
+ });
+ });
+});