summaryrefslogtreecommitdiff
path: root/spec/javascripts
diff options
context:
space:
mode:
authorSimon Knox <psimyn@gmail.com>2018-02-07 20:05:38 +1100
committerSimon Knox <psimyn@gmail.com>2018-02-07 20:05:38 +1100
commit4e91d397833eb10e9eb64a48387c441be2922dfb (patch)
tree079cbe95e6b0ac773987dd2ccedb98b1ded9681b /spec/javascripts
parentb68e473e7bb2b64e1a36c54f9ced10ffe5a96763 (diff)
parent4457cf9d178dc9912fd9c16427ad81b389179d00 (diff)
downloadgitlab-ce-snake-case.tar.gz
Merge branch 'master' into snake-casesnake-case
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/api_spec.js177
-rw-r--r--spec/javascripts/behaviors/secret_values_spec.js110
-rw-r--r--spec/javascripts/blob/notebook/index_spec.js6
-rw-r--r--spec/javascripts/blob/viewer/index_spec.js36
-rw-r--r--spec/javascripts/boards/board_card_spec.js2
-rw-r--r--spec/javascripts/boards/board_list_spec.js2
-rw-r--r--spec/javascripts/boards/board_new_issue_spec.js2
-rw-r--r--spec/javascripts/boards/boards_store_spec.js2
-rw-r--r--spec/javascripts/boards/list_spec.js2
-rw-r--r--spec/javascripts/ci_variable_list/ci_variable_list_spec.js163
-rw-r--r--spec/javascripts/ci_variable_list/native_form_variable_list_spec.js30
-rw-r--r--spec/javascripts/clusters/clusters_bundle_spec.js37
-rw-r--r--spec/javascripts/clusters/clusters_index_spec.js58
-rw-r--r--spec/javascripts/clusters/stores/clusters_store_spec.js1
-rw-r--r--spec/javascripts/collapsed_sidebar_todo_spec.js139
-rw-r--r--spec/javascripts/commit/commit_pipeline_status_component_spec.js104
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js5
-rw-r--r--spec/javascripts/commits_spec.js43
-rw-r--r--spec/javascripts/create_item_dropdown_spec.js139
-rw-r--r--spec/javascripts/environments/environment_item_spec.js4
-rw-r--r--spec/javascripts/feature_highlight/feature_highlight_helper_spec.js231
-rw-r--r--spec/javascripts/feature_highlight/feature_highlight_options_spec.js30
-rw-r--r--spec/javascripts/feature_highlight/feature_highlight_spec.js131
-rw-r--r--spec/javascripts/fixtures/clusters.rb15
-rw-r--r--spec/javascripts/fixtures/jobs.rb2
-rw-r--r--spec/javascripts/fixtures/pipeline_schedules.rb43
-rw-r--r--spec/javascripts/fixtures/projects.json2
-rw-r--r--spec/javascripts/fly_out_nav_spec.js32
-rw-r--r--spec/javascripts/gfm_auto_complete_spec.js13
-rw-r--r--spec/javascripts/helpers/class_spec_helper_spec.js20
-rw-r--r--spec/javascripts/helpers/user_mock_data_helper.js2
-rw-r--r--spec/javascripts/integrations/integration_settings_form_spec.js128
-rw-r--r--spec/javascripts/issuable_spec.js26
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js2
-rw-r--r--spec/javascripts/issue_spec.js144
-rw-r--r--spec/javascripts/job_spec.js261
-rw-r--r--spec/javascripts/jobs/job_details_mediator_spec.js8
-rw-r--r--spec/javascripts/jobs/mock_data.js8
-rw-r--r--spec/javascripts/labels_issue_sidebar_spec.js43
-rw-r--r--spec/javascripts/lib/utils/ajax_cache_spec.js68
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js51
-rw-r--r--spec/javascripts/lib/utils/users_cache_spec.js4
-rw-r--r--spec/javascripts/merge_request_spec.js28
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js96
-rw-r--r--spec/javascripts/mini_pipeline_graph_dropdown_spec.js73
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js2
-rw-r--r--spec/javascripts/notes/mock_data.js2
-rw-r--r--spec/javascripts/notes_spec.js212
-rw-r--r--spec/javascripts/pager_spec.js81
-rw-r--r--spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js95
-rw-r--r--spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js145
-rw-r--r--spec/javascripts/pipelines/pipelines_table_row_spec.js7
-rw-r--r--spec/javascripts/pipelines/pipelines_table_spec.js5
-rw-r--r--spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js44
-rw-r--r--spec/javascripts/repo/components/new_dropdown/modal_spec.js6
-rw-r--r--spec/javascripts/repo/components/new_dropdown/upload_spec.js6
-rw-r--r--spec/javascripts/repo/components/repo_commit_section_spec.js6
-rw-r--r--spec/javascripts/repo/stores/actions_spec.js32
-rw-r--r--spec/javascripts/right_sidebar_spec.js26
-rw-r--r--spec/javascripts/sidebar/mock_data.js34
-rw-r--r--spec/javascripts/sidebar/sidebar_store_spec.js6
-rw-r--r--spec/javascripts/test_bundle.js10
-rw-r--r--spec/javascripts/toggle_buttons_spec.js120
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js58
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js79
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js269
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js79
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js131
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js44
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js36
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js106
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js138
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js123
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js33
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js131
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js208
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js34
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js10
-rw-r--r--spec/javascripts/vue_shared/components/confirmation_input_spec.js63
-rw-r--r--spec/javascripts/vue_shared/components/modal_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js9
81 files changed, 3101 insertions, 1814 deletions
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index 2aa4fb1f6c6..cf3a76d0d2e 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -1,3 +1,5 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import Api from '~/api';
describe('Api', () => {
@@ -7,20 +9,17 @@ describe('Api', () => {
api_version: dummyApiVersion,
relative_url_root: dummyUrlRoot,
};
- const dummyResponse = 'hello from outer space!';
- const sendDummyResponse = () => {
- const deferred = $.Deferred();
- deferred.resolve(dummyResponse);
- return deferred.promise();
- };
let originalGon;
+ let mock;
beforeEach(() => {
+ mock = new MockAdapter(axios);
originalGon = window.gon;
window.gon = Object.assign({}, dummyGon);
});
afterEach(() => {
+ mock.restore();
window.gon = originalGon;
});
@@ -38,15 +37,13 @@ describe('Api', () => {
describe('group', () => {
it('fetches a group', (done) => {
const groupId = '123456';
- const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}.json`;
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- return sendDummyResponse();
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}`;
+ mock.onGet(expectedUrl).reply(200, {
+ name: 'test',
});
Api.group(groupId, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.name).toBe('test');
done();
});
});
@@ -57,19 +54,13 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups.json`;
- const expectedData = Object.assign({
- search: query,
- per_page: 20,
- }, options);
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.groups(query, options, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
done();
});
});
@@ -79,19 +70,13 @@ describe('Api', () => {
it('fetches namespaces', (done) => {
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/namespaces.json`;
- const expectedData = {
- search: query,
- per_page: 20,
- };
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.namespaces(query, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
done();
});
});
@@ -103,21 +88,13 @@ describe('Api', () => {
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
window.gon.current_user_id = 1;
- const expectedData = Object.assign({
- search: query,
- per_page: 20,
- membership: true,
- simple: true,
- }, options);
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.projects(query, options, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
done();
});
});
@@ -126,20 +103,13 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
- const expectedData = Object.assign({
- search: query,
- per_page: 20,
- simple: true,
- }, options);
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.projects(query, options, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
done();
});
});
@@ -154,16 +124,16 @@ describe('Api', () => {
const expectedData = {
label: labelData,
};
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.type).toEqual('POST');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
+ mock.onPost(expectedUrl).reply((config) => {
+ expect(config.data).toBe(JSON.stringify(expectedData));
+
+ return [200, {
+ name: 'test',
+ }];
});
Api.newLabel(namespace, project, labelData, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.name).toBe('test');
done();
});
});
@@ -174,19 +144,13 @@ describe('Api', () => {
const groupId = '123456';
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/projects.json`;
- const expectedData = {
- search: query,
- per_page: 20,
- };
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.groupProjects(groupId, query, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
done();
});
});
@@ -197,14 +161,10 @@ describe('Api', () => {
const licenseKey = "driver's license";
const data = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/licenses/${licenseKey}`;
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.data).toEqual(data);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, 'test');
Api.licenseText(licenseKey, data, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response).toBe('test');
done();
});
});
@@ -214,13 +174,10 @@ describe('Api', () => {
it('fetches a gitignore text', (done) => {
const gitignoreKey = 'ignore git';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/gitignores/${gitignoreKey}`;
- spyOn(jQuery, 'get').and.callFake((url, callback) => {
- expect(url).toEqual(expectedUrl);
- callback(dummyResponse);
- });
+ mock.onGet(expectedUrl).reply(200, 'test');
Api.gitignoreText(gitignoreKey, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response).toBe('test');
done();
});
});
@@ -230,13 +187,10 @@ describe('Api', () => {
it('fetches a .gitlab-ci.yml', (done) => {
const gitlabCiYmlKey = 'Y CI ML';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/gitlab_ci_ymls/${gitlabCiYmlKey}`;
- spyOn(jQuery, 'get').and.callFake((url, callback) => {
- expect(url).toEqual(expectedUrl);
- callback(dummyResponse);
- });
+ mock.onGet(expectedUrl).reply(200, 'test');
Api.gitlabCiYml(gitlabCiYmlKey, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response).toBe('test');
done();
});
});
@@ -246,13 +200,10 @@ describe('Api', () => {
it('fetches a Dockerfile', (done) => {
const dockerfileYmlKey = 'a giant whale';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/dockerfiles/${dockerfileYmlKey}`;
- spyOn(jQuery, 'get').and.callFake((url, callback) => {
- expect(url).toEqual(expectedUrl);
- callback(dummyResponse);
- });
+ mock.onGet(expectedUrl).reply(200, 'test');
Api.dockerfileYml(dockerfileYmlKey, (response) => {
- expect(response).toBe(dummyResponse);
+ expect(response).toBe('test');
done();
});
});
@@ -262,17 +213,13 @@ describe('Api', () => {
it('fetches an issue template', (done) => {
const namespace = 'some namespace';
const project = 'some project';
- const templateKey = 'template key';
+ const templateKey = ' template #%?.key ';
const templateType = 'template type';
- const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${templateKey}`;
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- return sendDummyResponse();
- });
+ const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${encodeURIComponent(templateKey)}`;
+ mock.onGet(expectedUrl).reply(200, 'test');
Api.issueTemplate(namespace, project, templateKey, templateType, (error, response) => {
- expect(error).toBe(null);
- expect(response).toBe(dummyResponse);
+ expect(response).toBe('test');
done();
});
});
@@ -283,20 +230,14 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users.json`;
- const expectedData = Object.assign({
- search: query,
- per_page: 20,
- }, options);
- spyOn(jQuery, 'ajax').and.callFake((request) => {
- expect(request.url).toEqual(expectedUrl);
- expect(request.dataType).toEqual('json');
- expect(request.data).toEqual(expectedData);
- return sendDummyResponse();
- });
+ mock.onGet(expectedUrl).reply(200, [{
+ name: 'test',
+ }]);
Api.users(query, options)
- .then((response) => {
- expect(response).toBe(dummyResponse);
+ .then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/behaviors/secret_values_spec.js b/spec/javascripts/behaviors/secret_values_spec.js
index 9eeae474e7d..38d9bba6868 100644
--- a/spec/javascripts/behaviors/secret_values_spec.js
+++ b/spec/javascripts/behaviors/secret_values_spec.js
@@ -1,16 +1,24 @@
import SecretValues from '~/behaviors/secret_values';
-function generateFixtureMarkup(secrets, isRevealed) {
+function generateValueMarkup(
+ secret,
+ valueClass = 'js-secret-value',
+ placeholderClass = 'js-secret-value-placeholder',
+) {
+ return `
+ <div class="${placeholderClass}">
+ ***
+ </div>
+ <div class="hide ${valueClass}">
+ ${secret}
+ </div>
+ `;
+}
+
+function generateFixtureMarkup(secrets, isRevealed, valueClass, placeholderClass) {
return `
<div class="js-secret-container">
- ${secrets.map(secret => `
- <div class="js-secret-value-placeholder">
- ***
- </div>
- <div class="hide js-secret-value">
- ${secret}
- </div>
- `).join('')}
+ ${secrets.map(secret => generateValueMarkup(secret, valueClass, placeholderClass)).join('')}
<button
class="js-secret-value-reveal-button"
data-secret-reveal-status="${isRevealed}"
@@ -21,11 +29,25 @@ function generateFixtureMarkup(secrets, isRevealed) {
`;
}
-function setupSecretFixture(secrets, isRevealed) {
+function setupSecretFixture(
+ secrets,
+ isRevealed,
+ valueClass = 'js-secret-value',
+ placeholderClass = 'js-secret-value-placeholder',
+) {
const wrapper = document.createElement('div');
- wrapper.innerHTML = generateFixtureMarkup(secrets, isRevealed);
-
- const secretValues = new SecretValues(wrapper.querySelector('.js-secret-container'));
+ wrapper.innerHTML = generateFixtureMarkup(
+ secrets,
+ isRevealed,
+ valueClass,
+ placeholderClass,
+ );
+
+ const secretValues = new SecretValues({
+ container: wrapper.querySelector('.js-secret-container'),
+ valueSelector: `.${valueClass}`,
+ placeholderSelector: `.${placeholderClass}`,
+ });
secretValues.init();
return wrapper;
@@ -49,7 +71,7 @@ describe('setupSecretValues', () => {
expect(revealButton.textContent).toEqual('Hide value');
});
- it('should value hidden initially', () => {
+ it('should have value hidden initially', () => {
const wrapper = setupSecretFixture(secrets, false);
const values = wrapper.querySelectorAll('.js-secret-value');
const placeholders = wrapper.querySelectorAll('.js-secret-value-placeholder');
@@ -143,4 +165,64 @@ describe('setupSecretValues', () => {
});
});
});
+
+ describe('with dynamic secrets', () => {
+ const secrets = ['mysecret123', 'happygoat456', 'tanuki789'];
+
+ it('should toggle values and placeholders', () => {
+ const wrapper = setupSecretFixture(secrets, false);
+ // Insert the new dynamic row
+ wrapper.querySelector('.js-secret-container').insertAdjacentHTML('afterbegin', generateValueMarkup('foobarbazdynamic'));
+
+ const revealButton = wrapper.querySelector('.js-secret-value-reveal-button');
+ const values = wrapper.querySelectorAll('.js-secret-value');
+ const placeholders = wrapper.querySelectorAll('.js-secret-value-placeholder');
+
+ revealButton.click();
+
+ expect(values.length).toEqual(4);
+ values.forEach((value) => {
+ expect(value.classList.contains('hide')).toEqual(false);
+ });
+ expect(placeholders.length).toEqual(4);
+ placeholders.forEach((placeholder) => {
+ expect(placeholder.classList.contains('hide')).toEqual(true);
+ });
+
+ revealButton.click();
+
+ expect(values.length).toEqual(4);
+ values.forEach((value) => {
+ expect(value.classList.contains('hide')).toEqual(true);
+ });
+ expect(placeholders.length).toEqual(4);
+ placeholders.forEach((placeholder) => {
+ expect(placeholder.classList.contains('hide')).toEqual(false);
+ });
+ });
+ });
+
+ describe('selector options', () => {
+ const secrets = ['mysecret123'];
+
+ it('should respect `valueSelector` and `placeholderSelector` options', () => {
+ const valueClass = 'js-some-custom-placeholder-selector';
+ const placeholderClass = 'js-some-custom-value-selector';
+
+ const wrapper = setupSecretFixture(secrets, false, valueClass, placeholderClass);
+ const values = wrapper.querySelectorAll(`.${valueClass}`);
+ const placeholders = wrapper.querySelectorAll(`.${placeholderClass}`);
+ const revealButton = wrapper.querySelector('.js-secret-value-reveal-button');
+
+ expect(values.length).toEqual(1);
+ expect(placeholders.length).toEqual(1);
+
+ revealButton.click();
+
+ expect(values.length).toEqual(1);
+ expect(values[0].classList.contains('hide')).toEqual(false);
+ expect(placeholders.length).toEqual(1);
+ expect(placeholders[0].classList.contains('hide')).toEqual(true);
+ });
+ });
});
diff --git a/spec/javascripts/blob/notebook/index_spec.js b/spec/javascripts/blob/notebook/index_spec.js
index df1b2c9960b..a143fc827d5 100644
--- a/spec/javascripts/blob/notebook/index_spec.js
+++ b/spec/javascripts/blob/notebook/index_spec.js
@@ -45,7 +45,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
@@ -96,7 +96,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
@@ -127,7 +127,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js
index cfa6650d85f..892411a6a40 100644
--- a/spec/javascripts/blob/viewer/index_spec.js
+++ b/spec/javascripts/blob/viewer/index_spec.js
@@ -1,28 +1,35 @@
/* eslint-disable no-new */
+import MockAdapter from 'axios-mock-adapter';
import BlobViewer from '~/blob/viewer/index';
+import axios from '~/lib/utils/axios_utils';
describe('Blob viewer', () => {
let blob;
+ let mock;
+
preloadFixtures('snippets/show.html.raw');
beforeEach(() => {
+ mock = new MockAdapter(axios);
+
loadFixtures('snippets/show.html.raw');
$('#modal-upload-blob').remove();
blob = new BlobViewer();
- spyOn($, 'ajax').and.callFake(() => {
- const d = $.Deferred();
-
- d.resolve({
- html: '<div>testing</div>',
- });
+ mock.onGet('http://test.host/snippets/1.json?viewer=rich').reply(200, {
+ html: '<div>testing</div>',
+ });
- return d.promise();
+ mock.onGet('http://test.host/snippets/1.json?viewer=simple').reply(200, {
+ html: '<div>testing</div>',
});
+
+ spyOn(axios, 'get').and.callThrough();
});
afterEach(() => {
+ mock.restore();
location.hash = '';
});
@@ -30,7 +37,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
- expect($.ajax).toHaveBeenCalled();
expect(
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]')
.classList.contains('hidden'),
@@ -46,7 +52,6 @@ describe('Blob viewer', () => {
new BlobViewer();
setTimeout(() => {
- expect($.ajax).toHaveBeenCalled();
expect(
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]')
.classList.contains('hidden'),
@@ -64,12 +69,8 @@ describe('Blob viewer', () => {
});
asyncClick()
+ .then(() => asyncClick())
.then(() => {
- expect($.ajax).toHaveBeenCalled();
- return asyncClick();
- })
- .then(() => {
- expect($.ajax.calls.count()).toBe(1);
expect(
document.querySelector('.blob-viewer[data-type="simple"]').getAttribute('data-loaded'),
).toBe('true');
@@ -122,7 +123,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
- expect($.ajax).toHaveBeenCalled();
expect(
copyButton.classList.contains('disabled'),
).toBeFalsy();
@@ -135,8 +135,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
- expect($.ajax).toHaveBeenCalled();
-
expect(
copyButton.getAttribute('data-original-title'),
).toBe('Copy source to clipboard');
@@ -171,14 +169,14 @@ describe('Blob viewer', () => {
it('sends AJAX request when switching to simple view', () => {
blob.switchToViewer('simple');
- expect($.ajax).toHaveBeenCalled();
+ expect(axios.get).toHaveBeenCalled();
});
it('does not send AJAX request when switching to rich view', () => {
blob.switchToViewer('simple');
blob.switchToViewer('rich');
- expect($.ajax.calls.count()).toBe(1);
+ expect(axios.get.calls.count()).toBe(1);
});
});
});
diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js
index 4e73fa1fe87..80a598e63bd 100644
--- a/spec/javascripts/boards/board_card_spec.js
+++ b/spec/javascripts/boards/board_card_spec.js
@@ -55,7 +55,7 @@ describe('Board card', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('returns false when detailIssue is empty', () => {
diff --git a/spec/javascripts/boards/board_list_spec.js b/spec/javascripts/boards/board_list_spec.js
index 9ffdac9be97..a5fcb10b9dd 100644
--- a/spec/javascripts/boards/board_list_spec.js
+++ b/spec/javascripts/boards/board_list_spec.js
@@ -60,7 +60,7 @@ describe('Board list component', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('renders component', () => {
diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js
index c62c537841c..e204985f039 100644
--- a/spec/javascripts/boards/board_new_issue_spec.js
+++ b/spec/javascripts/boards/board_new_issue_spec.js
@@ -58,7 +58,7 @@ describe('Issue boards new issue form', () => {
afterEach(() => {
vm.$destroy();
- mock.reset();
+ mock.restore();
});
it('calls submit if submit button is clicked', (done) => {
diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js
index 49fb20f4c84..8411f4dd8a6 100644
--- a/spec/javascripts/boards/boards_store_spec.js
+++ b/spec/javascripts/boards/boards_store_spec.js
@@ -35,7 +35,7 @@ describe('Store', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('starts with a blank state', () => {
diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js
index e5e7b48228b..34964b20b05 100644
--- a/spec/javascripts/boards/list_spec.js
+++ b/spec/javascripts/boards/list_spec.js
@@ -30,7 +30,7 @@ describe('List model', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('gets issues when created', (done) => {
diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
new file mode 100644
index 00000000000..0170ab458d4
--- /dev/null
+++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
@@ -0,0 +1,163 @@
+import VariableList from '~/ci_variable_list/ci_variable_list';
+import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper';
+
+describe('VariableList', () => {
+ preloadFixtures('pipeline_schedules/edit.html.raw');
+ preloadFixtures('pipeline_schedules/edit_with_variables.html.raw');
+
+ let $wrapper;
+ let variableList;
+
+ describe('with only key/value inputs', () => {
+ describe('with no variables', () => {
+ beforeEach(() => {
+ loadFixtures('pipeline_schedules/edit.html.raw');
+ $wrapper = $('.js-ci-variable-list-section');
+
+ variableList = new VariableList({
+ container: $wrapper,
+ formField: 'schedule',
+ });
+ variableList.init();
+ });
+
+ it('should remove the row when clicking the remove button', () => {
+ $wrapper.find('.js-row-remove-button').trigger('click');
+
+ expect($wrapper.find('.js-row').length).toBe(0);
+ });
+
+ it('should add another row when editing the last rows key input', () => {
+ const $row = $wrapper.find('.js-row');
+ $row.find('.js-ci-variable-input-key')
+ .val('foo')
+ .trigger('input');
+
+ expect($wrapper.find('.js-row').length).toBe(2);
+
+ // Check for the correct default in the new row
+ const $keyInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key');
+ expect($keyInput.val()).toBe('');
+ });
+
+ it('should add another row when editing the last rows value textarea', () => {
+ const $row = $wrapper.find('.js-row');
+ $row.find('.js-ci-variable-input-value')
+ .val('foo')
+ .trigger('input');
+
+ expect($wrapper.find('.js-row').length).toBe(2);
+
+ // Check for the correct default in the new row
+ const $valueInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key');
+ expect($valueInput.val()).toBe('');
+ });
+
+ it('should remove empty row after blurring', () => {
+ const $row = $wrapper.find('.js-row');
+ $row.find('.js-ci-variable-input-key')
+ .val('foo')
+ .trigger('input');
+
+ expect($wrapper.find('.js-row').length).toBe(2);
+
+ $row.find('.js-ci-variable-input-key')
+ .val('')
+ .trigger('input')
+ .trigger('blur');
+
+ expect($wrapper.find('.js-row').length).toBe(1);
+ });
+ });
+
+ describe('with persisted variables', () => {
+ beforeEach(() => {
+ loadFixtures('pipeline_schedules/edit_with_variables.html.raw');
+ $wrapper = $('.js-ci-variable-list-section');
+
+ variableList = new VariableList({
+ container: $wrapper,
+ formField: 'schedule',
+ });
+ variableList.init();
+ });
+
+ it('should have "Reveal values" button initially when there are already variables', () => {
+ expect($wrapper.find('.js-secret-value-reveal-button').text()).toBe('Reveal values');
+ });
+
+ it('should reveal hidden values', () => {
+ const $row = $wrapper.find('.js-row:first-child');
+ 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);
+
+ // Reveal values
+ $wrapper.find('.js-secret-value-reveal-button').click();
+
+ expect($placeholder.hasClass('hide')).toBe(true);
+ expect($inputValue.hasClass('hide')).toBe(false);
+ });
+ });
+ });
+
+ describe('with all inputs(key, value, protected)', () => {
+ beforeEach(() => {
+ // This markup will be replaced with a fixture when we can render the
+ // CI/CD settings page with the new dynamic variable list in https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4110
+ $wrapper = $(`<form class="js-variable-list">
+ <ul>
+ <li class="js-row">
+ <div class="ci-variable-body-item">
+ <input class="js-ci-variable-input-key" name="variables[variables_attributes][][key]">
+ </div>
+
+ <div class="ci-variable-body-item">
+ <textarea class="js-ci-variable-input-value" name="variables[variables_attributes][][value]"></textarea>
+ </div>
+
+ <div class="ci-variable-body-item ci-variable-protected-item">
+ <button type="button" class="js-project-feature-toggle project-feature-toggle">
+ <input
+ type="hidden"
+ class="js-ci-variable-input-protected js-project-feature-toggle-input"
+ name="variables[variables_attributes][][protected]"
+ value="true"
+ />
+ </button>
+ </div>
+
+ <button type="button" class="js-row-remove-button"></button>
+ </li>
+ </ul>
+ <button type="button" class="js-secret-value-reveal-button">
+ Reveal values
+ </button>
+ </form>`);
+
+ variableList = new VariableList({
+ container: $wrapper,
+ formField: 'variables',
+ });
+ variableList.init();
+ });
+
+ it('should add another row when editing the last rows protected checkbox', (done) => {
+ const $row = $wrapper.find('.js-row:last-child');
+ $row.find('.ci-variable-protected-item .js-project-feature-toggle').click();
+
+ getSetTimeoutPromise()
+ .then(() => {
+ expect($wrapper.find('.js-row').length).toBe(2);
+
+ // Check for the correct default in the new row
+ const $protectedInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-protected');
+ expect($protectedInput.val()).toBe('true');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js
new file mode 100644
index 00000000000..eb508a7f059
--- /dev/null
+++ b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js
@@ -0,0 +1,30 @@
+import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list';
+
+describe('NativeFormVariableList', () => {
+ preloadFixtures('pipeline_schedules/edit.html.raw');
+
+ let $wrapper;
+
+ beforeEach(() => {
+ loadFixtures('pipeline_schedules/edit.html.raw');
+ $wrapper = $('.js-ci-variable-list-section');
+
+ setupNativeFormVariableList({
+ container: $wrapper,
+ formField: 'schedule',
+ });
+ });
+
+ describe('onFormSubmit', () => {
+ it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => {
+ const $row = $wrapper.find('.js-row');
+ expect($row.find('.js-ci-variable-input-key').attr('name')).toBe('schedule[variables_attributes][][key]');
+ expect($row.find('.js-ci-variable-input-value').attr('name')).toBe('schedule[variables_attributes][][value]');
+
+ $wrapper.closest('form').trigger('trigger-submit');
+
+ expect($row.find('.js-ci-variable-input-key').attr('name')).toBe('');
+ expect($row.find('.js-ci-variable-input-value').attr('name')).toBe('');
+ });
+ });
+});
diff --git a/spec/javascripts/clusters/clusters_bundle_spec.js b/spec/javascripts/clusters/clusters_bundle_spec.js
index f5be9ea0fb2..a9e244e523d 100644
--- a/spec/javascripts/clusters/clusters_bundle_spec.js
+++ b/spec/javascripts/clusters/clusters_bundle_spec.js
@@ -23,16 +23,24 @@ describe('Clusters', () => {
});
describe('toggle', () => {
- it('should update the button and the input field on click', () => {
- cluster.toggleButton.click();
+ it('should update the button and the input field on click', (done) => {
+ const toggleButton = document.querySelector('.js-cluster-enable-toggle-area .js-project-feature-toggle');
+ const toggleInput = document.querySelector('.js-cluster-enable-toggle-area .js-project-feature-toggle-input');
- expect(
- cluster.toggleButton.classList,
- ).not.toContain('is-checked');
+ toggleButton.click();
- expect(
- cluster.toggleInput.getAttribute('value'),
- ).toEqual('false');
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(
+ toggleButton.classList,
+ ).not.toContain('is-checked');
+
+ expect(
+ toggleInput.getAttribute('value'),
+ ).toEqual('false');
+ })
+ .then(done)
+ .catch(done.fail);
});
});
@@ -63,7 +71,8 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLABLE, title: 'Helm Tiller' },
});
- expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeNull();
+ const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
+ expect(flashMessage).toBeNull();
});
it('shows an alert when something gets newly installed', () => {
@@ -75,8 +84,9 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLED, title: 'Helm Tiller' },
});
- expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
- expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller was successfully installed on your cluster');
+ const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
+ expect(flashMessage).not.toBeNull();
+ expect(flashMessage.textContent.trim()).toEqual('Helm Tiller was successfully installed on your Kubernetes cluster');
});
it('shows an alert when multiple things gets newly installed', () => {
@@ -90,8 +100,9 @@ describe('Clusters', () => {
ingress: { status: APPLICATION_INSTALLED, title: 'Ingress' },
});
- expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
- expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your cluster');
+ const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
+ expect(flashMessage).not.toBeNull();
+ expect(flashMessage.textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your Kubernetes cluster');
});
});
diff --git a/spec/javascripts/clusters/clusters_index_spec.js b/spec/javascripts/clusters/clusters_index_spec.js
deleted file mode 100644
index 0a8b63ed5b4..00000000000
--- a/spec/javascripts/clusters/clusters_index_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import setClusterTableToggles from '~/clusters/clusters_index';
-import { setTimeout } from 'core-js/library/web/timers';
-
-describe('Clusters table', () => {
- preloadFixtures('clusters/index_cluster.html.raw');
- let mock;
-
- beforeEach(() => {
- loadFixtures('clusters/index_cluster.html.raw');
- mock = new MockAdapter(axios);
- setClusterTableToggles();
- });
-
- describe('update cluster', () => {
- it('renders loading state while request is made', () => {
- const button = document.querySelector('.js-toggle-cluster-list');
-
- button.click();
-
- expect(button.classList).toContain('is-loading');
- expect(button.getAttribute('disabled')).toEqual('true');
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('shows updated state after sucessfull request', (done) => {
- mock.onPut().reply(200, {}, {});
- const button = document.querySelector('.js-toggle-cluster-list');
- button.click();
-
- expect(button.classList).toContain('is-loading');
-
- setTimeout(() => {
- expect(button.classList).not.toContain('is-loading');
- expect(button.classList).not.toContain('is-checked');
- done();
- }, 0);
- });
-
- it('shows inital state after failed request', (done) => {
- mock.onPut().reply(500, {}, {});
- const button = document.querySelector('.js-toggle-cluster-list');
-
- button.click();
- expect(button.classList).toContain('is-loading');
-
- setTimeout(() => {
- expect(button.classList).not.toContain('is-loading');
- expect(button.classList).toContain('is-checked');
- done();
- }, 0);
- });
- });
-});
diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js
index ec2889355e6..726a4ed30de 100644
--- a/spec/javascripts/clusters/stores/clusters_store_spec.js
+++ b/spec/javascripts/clusters/stores/clusters_store_spec.js
@@ -58,6 +58,7 @@ describe('Clusters Store', () => {
expect(store.state).toEqual({
helpPath: null,
+ ingressHelpPath: null,
status: mockResponseData.status,
statusReason: mockResponseData.status_reason,
applications: {
diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js
index 5026eaafaca..2abf52a1676 100644
--- a/spec/javascripts/collapsed_sidebar_todo_spec.js
+++ b/spec/javascripts/collapsed_sidebar_todo_spec.js
@@ -1,10 +1,14 @@
/* eslint-disable no-new */
import _ from 'underscore';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import Sidebar from '~/right_sidebar';
+import timeoutPromise from './helpers/set_timeout_promise_helper';
describe('Issuable right sidebar collapsed todo toggle', () => {
const fixtureName = 'issues/open-issue.html.raw';
const jsonFixtureName = 'todos/todos.json';
+ let mock;
preloadFixtures(fixtureName);
preloadFixtures(jsonFixtureName);
@@ -19,19 +23,26 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document.querySelector('.js-right-sidebar')
.classList.toggle('right-sidebar-collapsed');
- spyOn(jQuery, 'ajax').and.callFake((res) => {
- const d = $.Deferred();
+ mock = new MockAdapter(axios);
+
+ mock.onPost(`${gl.TEST_HOST}/frontend-fixtures/issues-project/todos`).reply(() => {
const response = _.clone(todoData);
- if (res.type === 'DELETE') {
- delete response.delete_path;
- }
+ return [200, response];
+ });
- d.resolve(response);
- return d.promise();
+ mock.onDelete(/(.*)\/dashboard\/todos\/\d+$/).reply(() => {
+ const response = _.clone(todoData);
+ delete response.delete_path;
+
+ return [200, response];
});
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('shows add todo button', () => {
expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon'),
@@ -52,71 +63,101 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
).toBe('Add todo');
});
- it('toggle todo state', () => {
+ it('toggle todo state', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
- ).not.toBeNull();
+ setTimeout(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
+ ).not.toBeNull();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .fa-check-square'),
- ).not.toBeNull();
- });
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .fa-check-square'),
+ ).not.toBeNull();
- it('toggle todo state of expanded todo toggle', () => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- expect(
- document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Mark done');
+ done();
+ });
});
- it('toggles todo button tooltip', () => {
+ it('toggle todo state of expanded todo toggle', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('data-original-title'),
- ).toBe('Mark done');
- });
-
- it('marks todo as done', () => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
+ setTimeout(() => {
+ expect(
+ document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
+ ).toBe('Mark done');
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
- ).not.toBeNull();
+ done();
+ });
+ });
+ it('toggles todo button tooltip', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
- ).toBeNull();
+ setTimeout(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('data-original-title'),
+ ).toBe('Mark done');
- expect(
- document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Add todo');
+ done();
+ });
});
- it('updates aria-label to mark done', () => {
+ it('marks todo as done', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
- ).toBe('Mark done');
+ timeoutPromise()
+ .then(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
+ ).not.toBeNull();
+
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
+ })
+ .then(timeoutPromise)
+ .then(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
+ ).toBeNull();
+
+ expect(
+ document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
+ ).toBe('Add todo');
+ })
+ .then(done)
+ .catch(done.fail);
});
- it('updates aria-label to add todo', () => {
+ it('updates aria-label to mark done', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
- ).toBe('Mark done');
+ setTimeout(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
+ ).toBe('Mark done');
+ done();
+ });
+ });
+
+ it('updates aria-label to add todo', (done) => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
- ).toBe('Add todo');
+ timeoutPromise()
+ .then(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
+ ).toBe('Mark done');
+
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
+ })
+ .then(timeoutPromise)
+ .then(() => {
+ expect(
+ document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'),
+ ).toBe('Add todo');
+ })
+ .then(done)
+ .catch(done.fail);
});
});
diff --git a/spec/javascripts/commit/commit_pipeline_status_component_spec.js b/spec/javascripts/commit/commit_pipeline_status_component_spec.js
new file mode 100644
index 00000000000..90f290e845e
--- /dev/null
+++ b/spec/javascripts/commit/commit_pipeline_status_component_spec.js
@@ -0,0 +1,104 @@
+import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
+import mountComponent from '../helpers/vue_mount_component_helper';
+
+describe('Commit pipeline status component', () => {
+ let vm;
+ let Component;
+ let mock;
+ const mockCiStatus = {
+ details_path: '/root/hello-world/pipelines/1',
+ favicon: 'canceled.ico',
+ group: 'canceled',
+ has_details: true,
+ icon: 'status_canceled',
+ label: 'canceled',
+ text: 'canceled',
+ };
+
+ beforeEach(() => {
+ Component = Vue.extend(commitPipelineStatus);
+ });
+
+ describe('While polling pipeline data succesfully', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet('/dummy/endpoint').reply(() => {
+ const res = Promise.resolve([200, {
+ pipelines: [
+ {
+ details: {
+ status: mockCiStatus,
+ },
+ },
+ ],
+ }]);
+ return res;
+ });
+ vm = mountComponent(Component, {
+ endpoint: '/dummy/endpoint',
+ });
+ });
+
+ afterEach(() => {
+ vm.poll.stop();
+ vm.$destroy();
+ mock.restore();
+ });
+
+ it('shows the loading icon when polling is starting', (done) => {
+ expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.loading-container')).toBe(null);
+ done();
+ });
+ });
+
+ it('contains a ciStatus when the polling is succesful ', (done) => {
+ setTimeout(() => {
+ expect(vm.ciStatus).toEqual(mockCiStatus);
+ done();
+ });
+ });
+
+ it('contains a ci-status icon when polling is succesful', (done) => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.ci-status-icon')).not.toBe(null);
+ expect(vm.$el.querySelector('.ci-status-icon').classList).toContain(`ci-status-icon-${mockCiStatus.group}`);
+ done();
+ });
+ });
+ });
+
+ describe('When polling data was not succesful', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet('/dummy/endpoint').reply(() => {
+ const res = Promise.reject([502, { }]);
+ return res;
+ });
+ vm = new Component({
+ props: {
+ endpoint: '/dummy/endpoint',
+ },
+ });
+ });
+
+ afterEach(() => {
+ vm.poll.stop();
+ vm.$destroy();
+ mock.restore();
+ });
+
+ it('calls an errorCallback', (done) => {
+ spyOn(vm, 'errorCallback').and.callThrough();
+ vm.$mount();
+ setTimeout(() => {
+ expect(vm.errorCallback.calls.count()).toEqual(1);
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index d62c2966a8b..0afe09d87bc 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -10,9 +10,10 @@ describe('Pipelines table in Commits and Merge requests', () => {
preloadFixtures(jsonFixtureName);
beforeEach(() => {
- PipelinesTable = Vue.extend(pipelinesTable);
const pipelines = getJSONFixture(jsonFixtureName).pipelines;
- pipeline = pipelines.find(p => p.id === 1);
+
+ PipelinesTable = Vue.extend(pipelinesTable);
+ pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
});
describe('successful request', () => {
diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js
index d0176520440..44ec9e4eabf 100644
--- a/spec/javascripts/commits_spec.js
+++ b/spec/javascripts/commits_spec.js
@@ -1,4 +1,6 @@
import 'vendor/jquery.endless-scroll';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import CommitsList from '~/commits';
describe('Commits List', () => {
@@ -43,30 +45,47 @@ describe('Commits List', () => {
describe('on entering input', () => {
let ajaxSpy;
+ let mock;
beforeEach(() => {
CommitsList.init(25);
CommitsList.searchField.val('');
spyOn(history, 'replaceState').and.stub();
- ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
- req.success({
- data: '<li>Result</li>',
- });
+ mock = new MockAdapter(axios);
+
+ mock.onGet('/h5bp/html5-boilerplate/commits/master').reply(200, {
+ html: '<li>Result</li>',
});
+
+ ajaxSpy = spyOn(axios, 'get').and.callThrough();
+ });
+
+ afterEach(() => {
+ mock.restore();
});
- it('should save the last search string', () => {
+ it('should save the last search string', (done) => {
CommitsList.searchField.val('GitLab');
- CommitsList.filterResults();
- expect(ajaxSpy).toHaveBeenCalled();
- expect(CommitsList.lastSearch).toEqual('GitLab');
+ CommitsList.filterResults()
+ .then(() => {
+ expect(ajaxSpy).toHaveBeenCalled();
+ expect(CommitsList.lastSearch).toEqual('GitLab');
+
+ done();
+ })
+ .catch(done.fail);
});
- it('should not make ajax call if the input does not change', () => {
- CommitsList.filterResults();
- expect(ajaxSpy).not.toHaveBeenCalled();
- expect(CommitsList.lastSearch).toEqual('');
+ it('should not make ajax call if the input does not change', (done) => {
+ CommitsList.filterResults()
+ .then(() => {
+ expect(ajaxSpy).not.toHaveBeenCalled();
+ expect(CommitsList.lastSearch).toEqual('');
+
+ done();
+ })
+ .catch(done.fail);
});
});
});
diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js
index c8b00a4f553..143137c23ec 100644
--- a/spec/javascripts/create_item_dropdown_spec.js
+++ b/spec/javascripts/create_item_dropdown_spec.js
@@ -18,54 +18,67 @@ describe('CreateItemDropdown', () => {
preloadFixtures('static/create_item_dropdown.html.raw');
let $wrapperEl;
+ let createItemDropdown;
+
+ function createItemAndClearInput(text) {
+ // Filter for the new item
+ $wrapperEl.find('.dropdown-input-field')
+ .val(text)
+ .trigger('input');
+
+ // Create the new item
+ const $createButton = $wrapperEl.find('.js-dropdown-create-new-item');
+ $createButton.click();
+
+ // Clear out the filter
+ $wrapperEl.find('.dropdown-input-field')
+ .val('')
+ .trigger('input');
+ }
beforeEach(() => {
loadFixtures('static/create_item_dropdown.html.raw');
$wrapperEl = $('.js-create-item-dropdown-fixture-root');
-
- // eslint-disable-next-line no-new
- new CreateItemDropdown({
- $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
- defaultToggleLabel: 'All variables',
- fieldName: 'variable[environment]',
- getData: (term, callback) => {
- callback(DROPDOWN_ITEM_DATA);
- },
- });
});
afterEach(() => {
$wrapperEl.remove();
});
- it('should have a dropdown item for each piece of data', () => {
- // Get the data in the dropdown
- $('.js-dropdown-menu-toggle').click();
+ describe('items', () => {
+ beforeEach(() => {
+ createItemDropdown = new CreateItemDropdown({
+ $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
+ defaultToggleLabel: 'All variables',
+ fieldName: 'variable[environment]',
+ getData: (term, callback) => {
+ callback(DROPDOWN_ITEM_DATA);
+ },
+ });
+ });
+
+ it('should have a dropdown item for each piece of data', () => {
+ // Get the data in the dropdown
+ $('.js-dropdown-menu-toggle').click();
- const $itemEls = $wrapperEl.find('.js-dropdown-content a');
- expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
+ const $itemEls = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
+ });
});
describe('created items', () => {
const NEW_ITEM_TEXT = 'foobarbaz';
- function createItemAndClearInput(text) {
- // Filter for the new item
- $wrapperEl.find('.dropdown-input-field')
- .val(text)
- .trigger('input');
-
- // Create the new item
- const $createButton = $wrapperEl.find('.js-dropdown-create-new-item');
- $createButton.click();
-
- // Clear out the filter
- $wrapperEl.find('.dropdown-input-field')
- .val('')
- .trigger('input');
- }
-
beforeEach(() => {
+ createItemDropdown = new CreateItemDropdown({
+ $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
+ defaultToggleLabel: 'All variables',
+ fieldName: 'variable[environment]',
+ getData: (term, callback) => {
+ callback(DROPDOWN_ITEM_DATA);
+ },
+ });
+
// Open the dropdown
$('.js-dropdown-menu-toggle').click();
@@ -103,4 +116,68 @@ describe('CreateItemDropdown', () => {
expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
});
});
+
+ describe('clearDropdown()', () => {
+ beforeEach(() => {
+ createItemDropdown = new CreateItemDropdown({
+ $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
+ defaultToggleLabel: 'All variables',
+ fieldName: 'variable[environment]',
+ getData: (term, callback) => {
+ callback(DROPDOWN_ITEM_DATA);
+ },
+ });
+ });
+
+ it('should clear all data and filter input', () => {
+ const filterInput = $wrapperEl.find('.dropdown-input-field');
+
+ // Get the data in the dropdown
+ $('.js-dropdown-menu-toggle').click();
+
+ // Filter for an item
+ filterInput
+ .val('one')
+ .trigger('input');
+
+ const $itemElsAfterFilter = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemElsAfterFilter.length).toEqual(1);
+
+ createItemDropdown.clearDropdown();
+
+ const $itemElsAfterClear = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemElsAfterClear.length).toEqual(0);
+ expect(filterInput.val()).toEqual('');
+ });
+ });
+
+ describe('createNewItemFromValue option', () => {
+ beforeEach(() => {
+ createItemDropdown = new CreateItemDropdown({
+ $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
+ defaultToggleLabel: 'All variables',
+ fieldName: 'variable[environment]',
+ getData: (term, callback) => {
+ callback(DROPDOWN_ITEM_DATA);
+ },
+ createNewItemFromValue: newValue => ({
+ title: `${newValue}-title`,
+ id: `${newValue}-id`,
+ text: `${newValue}-text`,
+ }),
+ });
+ });
+
+ it('all items go through createNewItemFromValue', () => {
+ // Get the data in the dropdown
+ $('.js-dropdown-menu-toggle').click();
+
+ createItemAndClearInput('new-item');
+
+ const $itemEls = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemEls.length).toEqual(1 + DROPDOWN_ITEM_DATA.length);
+ expect($($itemEls[3]).text()).toEqual('new-item-text');
+ expect($wrapperEl.find('.dropdown-toggle-text').text()).toEqual('new-item-title');
+ });
+ });
});
diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js
index 0e141adb628..7a34126eef7 100644
--- a/spec/javascripts/environments/environment_item_spec.js
+++ b/spec/javascripts/environments/environment_item_spec.js
@@ -68,7 +68,7 @@ describe('Environment item', () => {
username: 'root',
id: 1,
state: 'active',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit: {
@@ -84,7 +84,7 @@ describe('Environment item', () => {
username: 'root',
id: 1,
state: 'active',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
diff --git a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js
new file mode 100644
index 00000000000..34ffc7b1016
--- /dev/null
+++ b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js
@@ -0,0 +1,231 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import {
+ getSelector,
+ togglePopover,
+ dismiss,
+ mouseleave,
+ mouseenter,
+ inserted,
+} from '~/feature_highlight/feature_highlight_helper';
+import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper';
+
+describe('feature highlight helper', () => {
+ describe('getSelector', () => {
+ it('returns js-feature-highlight selector', () => {
+ const highlightId = 'highlightId';
+ expect(getSelector(highlightId)).toEqual(`.js-feature-highlight[data-highlight=${highlightId}]`);
+ });
+ });
+
+ describe('togglePopover', () => {
+ describe('togglePopover(true)', () => {
+ it('returns true when popover is shown', () => {
+ const context = {
+ hasClass: () => false,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ expect(togglePopover.call(context, true)).toEqual(true);
+ });
+
+ it('returns false when popover is already shown', () => {
+ const context = {
+ hasClass: () => true,
+ };
+
+ expect(togglePopover.call(context, true)).toEqual(false);
+ });
+
+ it('shows popover', (done) => {
+ const context = {
+ hasClass: () => false,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ spyOn(context, 'popover').and.callFake((method) => {
+ expect(method).toEqual('show');
+ done();
+ });
+
+ togglePopover.call(context, true);
+ });
+
+ it('adds disable-animation and js-popover-show class', (done) => {
+ const context = {
+ hasClass: () => false,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ spyOn(context, 'toggleClass').and.callFake((classNames, show) => {
+ expect(classNames).toEqual('disable-animation js-popover-show');
+ expect(show).toEqual(true);
+ done();
+ });
+
+ togglePopover.call(context, true);
+ });
+ });
+
+ describe('togglePopover(false)', () => {
+ it('returns true when popover is hidden', () => {
+ const context = {
+ hasClass: () => true,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ expect(togglePopover.call(context, false)).toEqual(true);
+ });
+
+ it('returns false when popover is already hidden', () => {
+ const context = {
+ hasClass: () => false,
+ };
+
+ expect(togglePopover.call(context, false)).toEqual(false);
+ });
+
+ it('hides popover', (done) => {
+ const context = {
+ hasClass: () => true,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ spyOn(context, 'popover').and.callFake((method) => {
+ expect(method).toEqual('hide');
+ done();
+ });
+
+ togglePopover.call(context, false);
+ });
+
+ it('removes disable-animation and js-popover-show class', (done) => {
+ const context = {
+ hasClass: () => true,
+ popover: () => {},
+ toggleClass: () => {},
+ };
+
+ spyOn(context, 'toggleClass').and.callFake((classNames, show) => {
+ expect(classNames).toEqual('disable-animation js-popover-show');
+ expect(show).toEqual(false);
+ done();
+ });
+
+ togglePopover.call(context, false);
+ });
+ });
+ });
+
+ describe('dismiss', () => {
+ let mock;
+ const context = {
+ hide: () => {},
+ attr: () => '/-/callouts/dismiss',
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ spyOn(togglePopover, 'call').and.callFake(() => {});
+ spyOn(context, 'hide').and.callFake(() => {});
+ dismiss.call(context);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('calls persistent dismissal endpoint', (done) => {
+ const spy = jasmine.createSpy('dismiss-endpoint-hit');
+ mock.onPost('/-/callouts/dismiss').reply(spy);
+
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(spy).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('calls hide popover', () => {
+ expect(togglePopover.call).toHaveBeenCalledWith(context, false);
+ });
+
+ it('calls hide', () => {
+ expect(context.hide).toHaveBeenCalled();
+ });
+ });
+
+ describe('mouseleave', () => {
+ it('calls hide popover if .popover:hover is false', () => {
+ const fakeJquery = {
+ length: 0,
+ };
+
+ spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn));
+ spyOn(togglePopover, 'call');
+ mouseleave();
+ expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), false);
+ });
+
+ it('does not call hide popover if .popover:hover is true', () => {
+ const fakeJquery = {
+ length: 1,
+ };
+
+ spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn));
+ spyOn(togglePopover, 'call');
+ mouseleave();
+ expect(togglePopover.call).not.toHaveBeenCalledWith(false);
+ });
+ });
+
+ describe('mouseenter', () => {
+ const context = {};
+
+ it('shows popover', () => {
+ spyOn(togglePopover, 'call').and.returnValue(false);
+ mouseenter.call(context);
+ expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), true);
+ });
+
+ it('registers mouseleave event if popover is showed', (done) => {
+ spyOn(togglePopover, 'call').and.returnValue(true);
+ spyOn($.fn, 'on').and.callFake((eventName) => {
+ expect(eventName).toEqual('mouseleave');
+ done();
+ });
+ mouseenter.call(context);
+ });
+
+ it('does not register mouseleave event if popover is not showed', () => {
+ spyOn(togglePopover, 'call').and.returnValue(false);
+ const spy = spyOn($.fn, 'on').and.callFake(() => {});
+ mouseenter.call(context);
+ expect(spy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('inserted', () => {
+ it('registers click event callback', (done) => {
+ const context = {
+ getAttribute: () => 'popoverId',
+ dataset: {
+ highlight: 'some-feature',
+ },
+ };
+
+ spyOn($.fn, 'on').and.callFake((event) => {
+ expect(event).toEqual('click');
+ done();
+ });
+ inserted.call(context);
+ });
+ });
+});
diff --git a/spec/javascripts/feature_highlight/feature_highlight_options_spec.js b/spec/javascripts/feature_highlight/feature_highlight_options_spec.js
new file mode 100644
index 00000000000..7f9425d8abe
--- /dev/null
+++ b/spec/javascripts/feature_highlight/feature_highlight_options_spec.js
@@ -0,0 +1,30 @@
+import domContentLoaded from '~/feature_highlight/feature_highlight_options';
+import bp from '~/breakpoints';
+
+describe('feature highlight options', () => {
+ describe('domContentLoaded', () => {
+ it('should not call highlightFeatures when breakpoint is xs', () => {
+ spyOn(bp, 'getBreakpointSize').and.returnValue('xs');
+
+ expect(domContentLoaded()).toBe(false);
+ });
+
+ it('should not call highlightFeatures when breakpoint is sm', () => {
+ spyOn(bp, 'getBreakpointSize').and.returnValue('sm');
+
+ expect(domContentLoaded()).toBe(false);
+ });
+
+ it('should not call highlightFeatures when breakpoint is md', () => {
+ spyOn(bp, 'getBreakpointSize').and.returnValue('md');
+
+ expect(domContentLoaded()).toBe(false);
+ });
+
+ it('should call highlightFeatures when breakpoint is lg', () => {
+ spyOn(bp, 'getBreakpointSize').and.returnValue('lg');
+
+ expect(domContentLoaded()).toBe(true);
+ });
+ });
+});
diff --git a/spec/javascripts/feature_highlight/feature_highlight_spec.js b/spec/javascripts/feature_highlight/feature_highlight_spec.js
new file mode 100644
index 00000000000..6e1b0429ab7
--- /dev/null
+++ b/spec/javascripts/feature_highlight/feature_highlight_spec.js
@@ -0,0 +1,131 @@
+import * as featureHighlightHelper from '~/feature_highlight/feature_highlight_helper';
+import * as featureHighlight from '~/feature_highlight/feature_highlight';
+
+describe('feature highlight', () => {
+ beforeEach(() => {
+ setFixtures(`
+ <div>
+ <div class="js-feature-highlight" data-highlight="test" data-highlight-priority="10" disabled>
+ Trigger
+ </div>
+ </div>
+ <div class="feature-highlight-popover-content">
+ Content
+ <div class="dismiss-feature-highlight">
+ Dismiss
+ </div>
+ </div>
+ `);
+ });
+
+ describe('setupFeatureHighlightPopover', () => {
+ const selector = '.js-feature-highlight[data-highlight=test]';
+ beforeEach(() => {
+ spyOn(window, 'addEventListener');
+ spyOn(window, 'removeEventListener');
+ featureHighlight.setupFeatureHighlightPopover('test', 0);
+ });
+
+ it('setup popover content', () => {
+ const $popoverContent = $('.feature-highlight-popover-content');
+ const outerHTML = $popoverContent.prop('outerHTML');
+
+ expect($(selector).data('content')).toEqual(outerHTML);
+ });
+
+ it('setup mouseenter', () => {
+ const toggleSpy = spyOn(featureHighlightHelper.togglePopover, 'call');
+ $(selector).trigger('mouseenter');
+
+ expect(toggleSpy).toHaveBeenCalledWith(jasmine.any(Object), true);
+ });
+
+ it('setup debounced mouseleave', (done) => {
+ const toggleSpy = spyOn(featureHighlightHelper.togglePopover, 'call');
+ $(selector).trigger('mouseleave');
+
+ // Even though we've set the debounce to 0ms, setTimeout is needed for the debounce
+ setTimeout(() => {
+ expect(toggleSpy).toHaveBeenCalledWith(jasmine.any(Object), false);
+ done();
+ }, 0);
+ });
+
+ it('setup inserted.bs.popover', () => {
+ $(selector).trigger('mouseenter');
+ const popoverId = $(selector).attr('aria-describedby');
+ const spyEvent = spyOnEvent(`#${popoverId} .dismiss-feature-highlight`, 'click');
+
+ $(`#${popoverId} .dismiss-feature-highlight`).click();
+ expect(spyEvent).toHaveBeenTriggered();
+ });
+
+ it('setup show.bs.popover', () => {
+ $(selector).trigger('show.bs.popover');
+ expect(window.addEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function));
+ });
+
+ it('setup hide.bs.popover', () => {
+ $(selector).trigger('hide.bs.popover');
+ expect(window.removeEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function));
+ });
+
+ it('removes disabled attribute', () => {
+ expect($('.js-feature-highlight').is(':disabled')).toEqual(false);
+ });
+
+ it('displays popover', () => {
+ expect($(selector).attr('aria-describedby')).toBeFalsy();
+ $(selector).trigger('mouseenter');
+ expect($(selector).attr('aria-describedby')).toBeTruthy();
+ });
+ });
+
+ describe('findHighestPriorityFeature', () => {
+ beforeEach(() => {
+ setFixtures(`
+ <div class="js-feature-highlight" data-highlight="test" data-highlight-priority="10" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-high-priority" data-highlight-priority="20" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-low-priority" data-highlight-priority="0" disabled></div>
+ `);
+ });
+
+ it('should pick the highest priority feature highlight', () => {
+ setFixtures(`
+ <div class="js-feature-highlight" data-highlight="test" data-highlight-priority="10" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-high-priority" data-highlight-priority="20" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-low-priority" data-highlight-priority="0" disabled></div>
+ `);
+
+ expect($('.js-feature-highlight').length).toBeGreaterThan(1);
+ expect(featureHighlight.findHighestPriorityFeature()).toEqual('test-high-priority');
+ });
+
+ it('should work when no priority is set', () => {
+ setFixtures(`
+ <div class="js-feature-highlight" data-highlight="test" disabled></div>
+ `);
+
+ expect(featureHighlight.findHighestPriorityFeature()).toEqual('test');
+ });
+
+ it('should pick the highest priority feature highlight when some have no priority set', () => {
+ setFixtures(`
+ <div class="js-feature-highlight" data-highlight="test-no-priority1" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test" data-highlight-priority="10" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-no-priority2" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-high-priority" data-highlight-priority="20" disabled></div>
+ <div class="js-feature-highlight" data-highlight="test-low-priority" data-highlight-priority="0" disabled></div>
+ `);
+
+ expect($('.js-feature-highlight').length).toBeGreaterThan(1);
+ expect(featureHighlight.findHighestPriorityFeature()).toEqual('test-high-priority');
+ });
+ });
+
+ describe('highlightFeatures', () => {
+ it('calls setupFeatureHighlightPopover', () => {
+ expect(featureHighlight.highlightFeatures()).toEqual('test');
+ });
+ });
+});
diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb
index d26ea3febe8..8e74c4f859c 100644
--- a/spec/javascripts/fixtures/clusters.rb
+++ b/spec/javascripts/fixtures/clusters.rb
@@ -31,19 +31,4 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
-
- context 'rendering non-empty state' do
- before do
- cluster
- end
-
- it 'clusters/index_cluster.html.raw' do |example|
- get :index,
- namespace_id: namespace,
- project_id: project
-
- expect(response).to be_success
- store_frontend_fixture(response, example.description)
- end
- end
end
diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb
index 87d131dfe28..6d5c6d5334f 100644
--- a/spec/javascripts/fixtures/jobs.rb
+++ b/spec/javascripts/fixtures/jobs.rb
@@ -7,7 +7,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'builds-project') }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
- let!(:build_with_artifacts) { create(:ci_build, :success, :artifacts, :trace, pipeline: pipeline, stage: 'test', artifacts_expire_at: Time.now + 18.months) }
+ let!(:build_with_artifacts) { create(:ci_build, :success, :artifacts, :trace_artifact, pipeline: pipeline, stage: 'test', artifacts_expire_at: Time.now + 18.months) }
let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline, stage: 'build') }
let!(:pending_build) { create(:ci_build, :pending, pipeline: pipeline, stage: 'deploy') }
diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb
new file mode 100644
index 00000000000..56f27ea7df1
--- /dev/null
+++ b/spec/javascripts/fixtures/pipeline_schedules.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:admin) { create(:admin) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project, :public, :repository) }
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: admin) }
+ let!(:pipeline_schedule_populated) { create(:ci_pipeline_schedule, project: project, owner: admin) }
+ let!(:pipeline_schedule_variable1) { create(:ci_pipeline_schedule_variable, key: 'foo', value: 'foovalue', pipeline_schedule: pipeline_schedule_populated) }
+ let!(:pipeline_schedule_variable2) { create(:ci_pipeline_schedule_variable, key: 'bar', value: 'barvalue', pipeline_schedule: pipeline_schedule_populated) }
+
+ render_views
+
+ before(:all) do
+ clean_frontend_fixtures('pipeline_schedules/')
+ end
+
+ before do
+ sign_in(admin)
+ end
+
+ it 'pipeline_schedules/edit.html.raw' do |example|
+ get :edit,
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: pipeline_schedule.id
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+
+ it 'pipeline_schedules/edit_with_variables.html.raw' do |example|
+ get :edit,
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: pipeline_schedule_populated.id
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+end
diff --git a/spec/javascripts/fixtures/projects.json b/spec/javascripts/fixtures/projects.json
index 1339ee00870..68a150f602a 100644
--- a/spec/javascripts/fixtures/projects.json
+++ b/spec/javascripts/fixtures/projects.json
@@ -14,7 +14,7 @@
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
"web_url": "http://localhost:3000/u/root"
},
"name": "test",
diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js
index a3fa07d5bc2..eb9330f5e5b 100644
--- a/spec/javascripts/fly_out_nav_spec.js
+++ b/spec/javascripts/fly_out_nav_spec.js
@@ -167,30 +167,26 @@ describe('Fly out sidebar navigation', () => {
describe('mouseEnterTopItems', () => {
beforeEach(() => {
- jasmine.clock().install();
-
el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute; top: 0; left: 100px; height: 200px;"></div>';
});
- afterEach(() => {
- jasmine.clock().uninstall();
- });
-
- it('shows sub-items after 0ms if no menu is open', () => {
+ it('shows sub-items after 0ms if no menu is open', (done) => {
mouseEnterTopItems(el);
expect(
getHideSubItemsInterval(),
).toBe(0);
- jasmine.clock().tick(0);
+ setTimeout(() => {
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).toBe('block');
- expect(
- el.querySelector('.sidebar-sub-level-items').style.display,
- ).toBe('block');
+ done();
+ });
});
- it('shows sub-items after 300ms if a menu is currently open', () => {
+ it('shows sub-items after 300ms if a menu is currently open', (done) => {
documentMouseMove({
clientX: el.getBoundingClientRect().left,
clientY: el.getBoundingClientRect().top,
@@ -203,17 +199,19 @@ describe('Fly out sidebar navigation', () => {
clientY: el.getBoundingClientRect().top + 10,
});
- mouseEnterTopItems(el);
+ mouseEnterTopItems(el, 0);
expect(
getHideSubItemsInterval(),
).toBe(300);
- jasmine.clock().tick(300);
+ setTimeout(() => {
+ expect(
+ el.querySelector('.sidebar-sub-level-items').style.display,
+ ).toBe('block');
- expect(
- el.querySelector('.sidebar-sub-level-items').style.display,
- ).toBe('block');
+ done();
+ });
});
});
diff --git a/spec/javascripts/gfm_auto_complete_spec.js b/spec/javascripts/gfm_auto_complete_spec.js
index 6f357306ec7..50a587ef351 100644
--- a/spec/javascripts/gfm_auto_complete_spec.js
+++ b/spec/javascripts/gfm_auto_complete_spec.js
@@ -130,16 +130,25 @@ describe('GfmAutoComplete', function () {
});
describe('should not match special sequences', () => {
- const ShouldNotBeFollowedBy = flags.concat(['\x00', '\x10', '\x3f', '\n', ' ']);
+ const shouldNotBeFollowedBy = flags.concat(['\x00', '\x10', '\x3f', '\n', ' ']);
+ const shouldNotBePrependedBy = ['`'];
flagsUseDefaultMatcher.forEach((atSign) => {
- ShouldNotBeFollowedBy.forEach((followedSymbol) => {
+ shouldNotBeFollowedBy.forEach((followedSymbol) => {
const seq = atSign + followedSymbol;
it(`should not match "${seq}"`, () => {
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
});
});
+
+ shouldNotBePrependedBy.forEach((prependedSymbol) => {
+ const seq = prependedSymbol + atSign;
+
+ it(`should not match "${seq}"`, () => {
+ expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
+ });
+ });
});
});
});
diff --git a/spec/javascripts/helpers/class_spec_helper_spec.js b/spec/javascripts/helpers/class_spec_helper_spec.js
index 686b8eaed31..1415ffb7eb3 100644
--- a/spec/javascripts/helpers/class_spec_helper_spec.js
+++ b/spec/javascripts/helpers/class_spec_helper_spec.js
@@ -3,7 +3,7 @@
import './class_spec_helper';
describe('ClassSpecHelper', () => {
- describe('itShouldBeAStaticMethod', function () {
+ describe('itShouldBeAStaticMethod', () => {
beforeEach(() => {
class TestClass {
instanceMethod() { this.prop = 'val'; }
@@ -14,23 +14,5 @@ describe('ClassSpecHelper', () => {
});
ClassSpecHelper.itShouldBeAStaticMethod(ClassSpecHelper, 'itShouldBeAStaticMethod');
-
- it('should have a defined spec', () => {
- expect(ClassSpecHelper.itShouldBeAStaticMethod(this.TestClass, 'staticMethod').description).toBe('should be a static method');
- });
-
- it('should pass for a static method', () => {
- const spec = ClassSpecHelper.itShouldBeAStaticMethod(this.TestClass, 'staticMethod');
- expect(spec.status()).toBe('passed');
- });
-
- it('should fail for an instance method', (done) => {
- const spec = ClassSpecHelper.itShouldBeAStaticMethod(this.TestClass, 'instanceMethod');
- spec.resultCallback = (result) => {
- expect(result.status).toBe('failed');
- done();
- };
- spec.execute();
- });
});
});
diff --git a/spec/javascripts/helpers/user_mock_data_helper.js b/spec/javascripts/helpers/user_mock_data_helper.js
index a9783ea065c..323fee3767e 100644
--- a/spec/javascripts/helpers/user_mock_data_helper.js
+++ b/spec/javascripts/helpers/user_mock_data_helper.js
@@ -4,7 +4,7 @@ export default {
for (let i = 0; i < numberUsers; i = i += 1) {
users.push(
{
- avatar: 'http://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: (i + 1),
name: `GitLab User ${i}`,
username: `gitlab${i}`,
diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js
index 9033eb9ce02..d0fba908e34 100644
--- a/spec/javascripts/integrations/integration_settings_form_spec.js
+++ b/spec/javascripts/integrations/integration_settings_form_spec.js
@@ -1,3 +1,5 @@
+import MockAdaptor from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import IntegrationSettingsForm from '~/integrations/integration_settings_form';
describe('IntegrationSettingsForm', () => {
@@ -109,91 +111,117 @@ describe('IntegrationSettingsForm', () => {
describe('testSettings', () => {
let integrationSettingsForm;
let formData;
+ let mock;
beforeEach(() => {
+ mock = new MockAdaptor(axios);
+
+ spyOn(axios, 'put').and.callThrough();
+
integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
formData = integrationSettingsForm.$form.serialize();
});
- it('should make an ajax request with provided `formData`', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ afterEach(() => {
+ mock.restore();
+ });
- integrationSettingsForm.testSettings(formData);
+ it('should make an ajax request with provided `formData`', (done) => {
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData);
- expect($.ajax).toHaveBeenCalledWith({
- type: 'PUT',
- url: integrationSettingsForm.testEndPoint,
- data: formData,
- });
+ done();
+ })
+ .catch(done.fail);
});
- it('should show error Flash with `Save anyway` action if ajax request responds with error in test', () => {
+ it('should show error Flash with `Save anyway` action if ajax request responds with error in test', (done) => {
const errorMessage = 'Test failed.';
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
-
- integrationSettingsForm.testSettings(formData);
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: true,
+ message: errorMessage,
+ service_response: 'some error',
+ });
- deferred.resolve({ error: true, message: errorMessage, service_response: 'some error' });
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ const $flashContainer = $('.flash-container');
+ expect($flashContainer.find('.flash-text').text().trim()).toEqual('Test failed. some error');
+ expect($flashContainer.find('.flash-action')).toBeDefined();
+ expect($flashContainer.find('.flash-action').text().trim()).toEqual('Save anyway');
- const $flashContainer = $('.flash-container');
- expect($flashContainer.find('.flash-text').text().trim()).toEqual('Test failed. some error');
- expect($flashContainer.find('.flash-action')).toBeDefined();
- expect($flashContainer.find('.flash-action').text().trim()).toEqual('Save anyway');
+ done();
+ })
+ .catch(done.fail);
});
- it('should submit form if ajax request responds without any error in test', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should submit form if ajax request responds without any error in test', (done) => {
+ spyOn(integrationSettingsForm.$form, 'submit');
- integrationSettingsForm.testSettings(formData);
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: false,
+ });
- spyOn(integrationSettingsForm.$form, 'submit');
- deferred.resolve({ error: false });
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
- expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
+ done();
+ })
+ .catch(done.fail);
});
- it('should submit form when clicked on `Save anyway` action of error Flash', () => {
- const errorMessage = 'Test failed.';
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should submit form when clicked on `Save anyway` action of error Flash', (done) => {
+ spyOn(integrationSettingsForm.$form, 'submit');
- integrationSettingsForm.testSettings(formData);
+ const errorMessage = 'Test failed.';
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: true,
+ message: errorMessage,
+ });
- deferred.resolve({ error: true, message: errorMessage });
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ const $flashAction = $('.flash-container .flash-action');
+ expect($flashAction).toBeDefined();
- const $flashAction = $('.flash-container .flash-action');
- expect($flashAction).toBeDefined();
+ $flashAction.get(0).click();
+ })
+ .then(() => {
+ expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
- spyOn(integrationSettingsForm.$form, 'submit');
- $flashAction.get(0).click();
- expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
+ done();
+ })
+ .catch(done.fail);
});
- it('should show error Flash if ajax request failed', () => {
+ it('should show error Flash if ajax request failed', (done) => {
const errorMessage = 'Something went wrong on our end.';
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- integrationSettingsForm.testSettings(formData);
+ mock.onPut(integrationSettingsForm.testEndPoint).networkError();
- deferred.reject();
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ expect($('.flash-container .flash-text').text().trim()).toEqual(errorMessage);
- expect($('.flash-container .flash-text').text().trim()).toEqual(errorMessage);
+ done();
+ })
+ .catch(done.fail);
});
- it('should always call `toggleSubmitBtnState` with `false` once request is completed', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
-
- integrationSettingsForm.testSettings(formData);
+ it('should always call `toggleSubmitBtnState` with `false` once request is completed', (done) => {
+ mock.onPut(integrationSettingsForm.testEndPoint).networkError();
spyOn(integrationSettingsForm, 'toggleSubmitBtnState');
- deferred.reject();
- expect(integrationSettingsForm.toggleSubmitBtnState).toHaveBeenCalledWith(false);
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ expect(integrationSettingsForm.toggleSubmitBtnState).toHaveBeenCalledWith(false);
+
+ done();
+ })
+ .catch(done.fail);
});
});
});
diff --git a/spec/javascripts/issuable_spec.js b/spec/javascripts/issuable_spec.js
index 5a9112716f4..d53ffecbd35 100644
--- a/spec/javascripts/issuable_spec.js
+++ b/spec/javascripts/issuable_spec.js
@@ -1,3 +1,5 @@
+import MockAdaptor from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import IssuableIndex from '~/issuable_index';
describe('Issuable', () => {
@@ -19,6 +21,8 @@ describe('Issuable', () => {
});
describe('resetIncomingEmailToken', () => {
+ let mock;
+
beforeEach(() => {
const element = document.createElement('a');
element.classList.add('incoming-email-token-reset');
@@ -30,14 +34,28 @@ describe('Issuable', () => {
document.body.appendChild(input);
Issuable = new IssuableIndex('issue_');
+
+ mock = new MockAdaptor(axios);
+
+ mock.onPut('foo').reply(200, {
+ new_address: 'testing123',
+ });
});
- it('should send request to reset email token', () => {
- spyOn(jQuery, 'ajax').and.callThrough();
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should send request to reset email token', (done) => {
+ spyOn(axios, 'put').and.callThrough();
document.querySelector('.incoming-email-token-reset').click();
- expect(jQuery.ajax).toHaveBeenCalled();
- expect(jQuery.ajax.calls.argsFor(0)[0].url).toEqual('foo');
+ setTimeout(() => {
+ expect(axios.put).toHaveBeenCalledWith('foo');
+ expect($('#issuable_email').val()).toBe('testing123');
+
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index 9280db072b3..1c9f48028f2 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -59,7 +59,7 @@ describe('Issuable output', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
realtimeRequestCount = 0;
vm.poll.stop();
diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js
index 2cd2e63b15d..177962ecf82 100644
--- a/spec/javascripts/issue_spec.js
+++ b/spec/javascripts/issue_spec.js
@@ -1,4 +1,6 @@
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import Issue from '~/issue';
import '~/lib/utils/text_utility';
@@ -68,40 +70,27 @@ describe('Issue', function() {
expect($btn).toHaveText(isIssueInitiallyOpen ? 'Close issue' : 'Reopen issue');
}
- describe('task lists', function() {
- beforeEach(function() {
- loadFixtures('issues/issue-with-task-list.html.raw');
- this.issue = new Issue();
- });
-
- it('submits an ajax request on tasklist:changed', function() {
- spyOn(jQuery, 'ajax').and.callFake(function(req) {
- expect(req.type).toBe('PATCH');
- expect(req.url).toBe(gl.TEST_HOST + '/frontend-fixtures/issues-project/issues/1.json'); // eslint-disable-line prefer-template
- expect(req.data.issue.description).not.toBe(null);
- });
-
- $('.js-task-list-field').trigger('tasklist:changed');
- });
- });
-
[true, false].forEach((isIssueInitiallyOpen) => {
describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, function() {
const action = isIssueInitiallyOpen ? 'close' : 'reopen';
+ let mock;
- function ajaxSpy(req) {
- if (req.url === this.$triggeredButton.attr('href')) {
- expect(req.type).toBe('PUT');
- expectNewBranchButtonState(true, false);
- return this.issueStateDeferred;
- } else if (req.url === Issue.createMrDropdownWrap.dataset.canCreatePath) {
- expect(req.type).toBe('GET');
+ function mockCloseButtonResponseSuccess(url, response) {
+ mock.onPut(url).reply(() => {
expectNewBranchButtonState(true, false);
- return this.canCreateBranchDeferred;
- }
- expect(req.url).toBe('unexpected');
- return null;
+ return [200, response];
+ });
+ }
+
+ function mockCloseButtonResponseError(url) {
+ mock.onPut(url).networkError();
+ }
+
+ function mockCanCreateBranch(canCreateBranch) {
+ mock.onGet(/(.*)\/can_create_branch$/).reply(200, {
+ can_create_branch: canCreateBranch,
+ });
}
beforeEach(function() {
@@ -111,6 +100,11 @@ describe('Issue', function() {
loadFixtures('issues/closed-issue.html.raw');
}
+ mock = new MockAdapter(axios);
+
+ mock.onGet(/(.*)\/related_branches$/).reply(200, {});
+ mock.onGet(/(.*)\/referenced_merge_requests$/).reply(200, {});
+
findElements(isIssueInitiallyOpen);
this.issue = new Issue();
expectIssueState(isIssueInitiallyOpen);
@@ -120,71 +114,89 @@ describe('Issue', function() {
this.$projectIssuesCounter = $('.issue_counter').first();
this.$projectIssuesCounter.text('1,001');
- this.issueStateDeferred = new jQuery.Deferred();
- this.canCreateBranchDeferred = new jQuery.Deferred();
+ spyOn(axios, 'get').and.callThrough();
+ });
- spyOn(jQuery, 'ajax').and.callFake(ajaxSpy.bind(this));
+ afterEach(() => {
+ mock.restore();
+ $('div.flash-alert').remove();
});
- it(`${action}s the issue`, function() {
- this.$triggeredButton.trigger('click');
- this.issueStateDeferred.resolve({
+ it(`${action}s the issue`, function(done) {
+ mockCloseButtonResponseSuccess(this.$triggeredButton.attr('href'), {
id: 34
});
- this.canCreateBranchDeferred.resolve({
- can_create_branch: !isIssueInitiallyOpen
- });
+ mockCanCreateBranch(!isIssueInitiallyOpen);
- expectIssueState(!isIssueInitiallyOpen);
- expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
- expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002');
- expectNewBranchButtonState(false, !isIssueInitiallyOpen);
+ this.$triggeredButton.trigger('click');
+
+ setTimeout(() => {
+ expectIssueState(!isIssueInitiallyOpen);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
+ expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002');
+ expectNewBranchButtonState(false, !isIssueInitiallyOpen);
+
+ done();
+ });
});
- it(`fails to ${action} the issue if saved:false`, function() {
- this.$triggeredButton.trigger('click');
- this.issueStateDeferred.resolve({
+ it(`fails to ${action} the issue if saved:false`, function(done) {
+ mockCloseButtonResponseSuccess(this.$triggeredButton.attr('href'), {
saved: false
});
- this.canCreateBranchDeferred.resolve({
- can_create_branch: isIssueInitiallyOpen
- });
+ mockCanCreateBranch(isIssueInitiallyOpen);
- expectIssueState(isIssueInitiallyOpen);
- expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
- expectErrorMessage();
- expect(this.$projectIssuesCounter.text()).toBe('1,001');
- expectNewBranchButtonState(false, isIssueInitiallyOpen);
+ this.$triggeredButton.trigger('click');
+
+ setTimeout(() => {
+ expectIssueState(isIssueInitiallyOpen);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
+ expectErrorMessage();
+ expect(this.$projectIssuesCounter.text()).toBe('1,001');
+ expectNewBranchButtonState(false, isIssueInitiallyOpen);
+
+ done();
+ });
});
- it(`fails to ${action} the issue if HTTP error occurs`, function() {
+ it(`fails to ${action} the issue if HTTP error occurs`, function(done) {
+ mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
+ mockCanCreateBranch(isIssueInitiallyOpen);
+
this.$triggeredButton.trigger('click');
- this.issueStateDeferred.reject();
- this.canCreateBranchDeferred.resolve({
- can_create_branch: isIssueInitiallyOpen
- });
- expectIssueState(isIssueInitiallyOpen);
- expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
- expectErrorMessage();
- expect(this.$projectIssuesCounter.text()).toBe('1,001');
- expectNewBranchButtonState(false, isIssueInitiallyOpen);
+ setTimeout(() => {
+ expectIssueState(isIssueInitiallyOpen);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
+ expectErrorMessage();
+ expect(this.$projectIssuesCounter.text()).toBe('1,001');
+ expectNewBranchButtonState(false, isIssueInitiallyOpen);
+
+ done();
+ });
});
it('disables the new branch button if Ajax call fails', function() {
+ mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
+ mock.onGet(/(.*)\/can_create_branch$/).networkError();
+
this.$triggeredButton.trigger('click');
- this.issueStateDeferred.reject();
- this.canCreateBranchDeferred.reject();
expectNewBranchButtonState(false, false);
});
- it('does not trigger Ajax call if new branch button is missing', function() {
+ it('does not trigger Ajax call if new branch button is missing', function(done) {
+ mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
Issue.$btnNewBranch = $();
this.canCreateBranchDeferred = null;
this.$triggeredButton.trigger('click');
- this.issueStateDeferred.reject();
+
+ setTimeout(() => {
+ expect(axios.get).not.toHaveBeenCalled();
+
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js
index feb341d22e6..03b58e9c1d0 100644
--- a/spec/javascripts/job_spec.js
+++ b/spec/javascripts/job_spec.js
@@ -1,3 +1,5 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import '~/lib/utils/datetime_utility';
@@ -6,11 +8,29 @@ import '~/breakpoints';
describe('Job', () => {
const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`;
+ let mock;
+ let response;
+
+ function waitForPromise() {
+ return new Promise(resolve => requestAnimationFrame(resolve));
+ }
preloadFixtures('builds/build-with-artifacts.html.raw');
beforeEach(() => {
loadFixtures('builds/build-with-artifacts.html.raw');
+
+ spyOn(urlUtils, 'visitUrl');
+
+ mock = new MockAdapter(axios);
+
+ mock.onGet(new RegExp(`${JOB_URL}/trace.json?(.*)`)).reply(() => [200, response]);
+ });
+
+ afterEach(() => {
+ mock.restore();
+
+ response = {};
});
describe('class constructor', () => {
@@ -55,170 +75,159 @@ describe('Job', () => {
});
describe('running build', () => {
- it('updates the build trace on an interval', function () {
- const deferred1 = $.Deferred();
- const deferred2 = $.Deferred();
- const deferred3 = $.Deferred();
- spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise());
- spyOn(urlUtils, 'visitUrl');
-
- deferred1.resolve({
+ it('updates the build trace on an interval', function (done) {
+ response = {
html: '<span>Update<span>',
status: 'running',
state: 'newstate',
append: true,
complete: false,
- });
-
- deferred2.resolve();
-
- deferred3.resolve({
- html: '<span>More</span>',
- status: 'running',
- state: 'finalstate',
- append: true,
- complete: true,
- });
+ };
this.job = new Job();
- expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
- expect(this.job.state).toBe('newstate');
-
- jasmine.clock().tick(4001);
-
- expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
- expect(this.job.state).toBe('finalstate');
+ waitForPromise()
+ .then(() => {
+ expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
+ expect(this.job.state).toBe('newstate');
+
+ response = {
+ html: '<span>More</span>',
+ status: 'running',
+ state: 'finalstate',
+ append: true,
+ complete: true,
+ };
+ })
+ .then(() => jasmine.clock().tick(4001))
+ .then(waitForPromise)
+ .then(() => {
+ expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
+ expect(this.job.state).toBe('finalstate');
+ })
+ .then(done)
+ .catch(done.fail);
});
- it('replaces the entire build trace', () => {
- const deferred1 = $.Deferred();
- const deferred2 = $.Deferred();
- const deferred3 = $.Deferred();
-
- spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise());
-
- spyOn(urlUtils, 'visitUrl');
-
- deferred1.resolve({
+ it('replaces the entire build trace', (done) => {
+ response = {
html: '<span>Update<span>',
status: 'running',
append: false,
complete: false,
- });
-
- deferred2.resolve();
-
- deferred3.resolve({
- html: '<span>Different</span>',
- status: 'running',
- append: false,
- });
+ };
this.job = new Job();
- expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
-
- jasmine.clock().tick(4001);
-
- expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/);
- expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
+ waitForPromise()
+ .then(() => {
+ expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
+
+ response = {
+ html: '<span>Different</span>',
+ status: 'running',
+ append: false,
+ };
+ })
+ .then(() => jasmine.clock().tick(4001))
+ .then(waitForPromise)
+ .then(() => {
+ expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/);
+ expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
describe('truncated information', () => {
describe('when size is less than total', () => {
- it('shows information about truncated log', () => {
- spyOn(urlUtils, 'visitUrl');
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
-
- deferred.resolve({
+ it('shows information about truncated log', (done) => {
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size: 50,
total: 100,
- });
+ };
this.job = new Job();
- expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden');
+ waitForPromise()
+ .then(() => {
+ expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden');
+ })
+ .then(done)
+ .catch(done.fail);
});
- it('shows the size in KiB', () => {
+ it('shows the size in KiB', (done) => {
const size = 50;
- spyOn(urlUtils, 'visitUrl');
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- deferred.resolve({
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size,
total: 100,
- });
+ };
this.job = new Job();
- expect(
- document.querySelector('.js-truncated-info-size').textContent.trim(),
- ).toEqual(`${numberToHumanSize(size)}`);
+ waitForPromise()
+ .then(() => {
+ expect(
+ document.querySelector('.js-truncated-info-size').textContent.trim(),
+ ).toEqual(`${numberToHumanSize(size)}`);
+ })
+ .then(done)
+ .catch(done.fail);
});
- it('shows incremented size', () => {
- const deferred1 = $.Deferred();
- const deferred2 = $.Deferred();
- const deferred3 = $.Deferred();
-
- spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise());
-
- spyOn(urlUtils, 'visitUrl');
-
- deferred1.resolve({
+ it('shows incremented size', (done) => {
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size: 50,
total: 100,
- });
-
- deferred2.resolve();
+ };
this.job = new Job();
- expect(
- document.querySelector('.js-truncated-info-size').textContent.trim(),
- ).toEqual(`${numberToHumanSize(50)}`);
-
- jasmine.clock().tick(4001);
-
- deferred3.resolve({
- html: '<span>Update</span>',
- status: 'success',
- append: true,
- size: 10,
- total: 100,
- });
-
- expect(
- document.querySelector('.js-truncated-info-size').textContent.trim(),
- ).toEqual(`${numberToHumanSize(60)}`);
+ waitForPromise()
+ .then(() => {
+ expect(
+ document.querySelector('.js-truncated-info-size').textContent.trim(),
+ ).toEqual(`${numberToHumanSize(50)}`);
+
+ response = {
+ html: '<span>Update</span>',
+ status: 'success',
+ append: true,
+ size: 10,
+ total: 100,
+ };
+ })
+ .then(() => jasmine.clock().tick(4001))
+ .then(waitForPromise)
+ .then(() => {
+ expect(
+ document.querySelector('.js-truncated-info-size').textContent.trim(),
+ ).toEqual(`${numberToHumanSize(60)}`);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('renders the raw link', () => {
- const deferred = $.Deferred();
- spyOn(urlUtils, 'visitUrl');
-
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- deferred.resolve({
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size: 50,
total: 100,
- });
+ };
this.job = new Job();
@@ -229,50 +238,50 @@ describe('Job', () => {
});
describe('when size is equal than total', () => {
- it('does not show the trunctated information', () => {
- const deferred = $.Deferred();
- spyOn(urlUtils, 'visitUrl');
-
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- deferred.resolve({
+ it('does not show the trunctated information', (done) => {
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size: 100,
total: 100,
- });
+ };
this.job = new Job();
- expect(document.querySelector('.js-truncated-info').classList).toContain('hidden');
+ waitForPromise()
+ .then(() => {
+ expect(document.querySelector('.js-truncated-info').classList).toContain('hidden');
+ })
+ .then(done)
+ .catch(done.fail);
});
});
});
describe('output trace', () => {
- beforeEach(() => {
- const deferred = $.Deferred();
- spyOn(urlUtils, 'visitUrl');
-
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- deferred.resolve({
+ beforeEach((done) => {
+ response = {
html: '<span>Update</span>',
status: 'success',
append: false,
size: 50,
total: 100,
- });
+ };
this.job = new Job();
+
+ waitForPromise()
+ .then(done)
+ .catch(done.fail);
});
it('should render trace controls', () => {
const controllers = document.querySelector('.controllers');
- expect(controllers.querySelector('.js-raw-link-controller')).toBeDefined();
- expect(controllers.querySelector('.js-erase-link')).toBeDefined();
- expect(controllers.querySelector('.js-scroll-up')).toBeDefined();
- expect(controllers.querySelector('.js-scroll-down')).toBeDefined();
+ expect(controllers.querySelector('.js-raw-link-controller')).not.toBeNull();
+ expect(controllers.querySelector('.js-scroll-up')).not.toBeNull();
+ expect(controllers.querySelector('.js-scroll-down')).not.toBeNull();
});
it('should render received output', () => {
@@ -285,13 +294,13 @@ describe('Job', () => {
describe('getBuildTrace', () => {
it('should request build trace with state parameter', (done) => {
- spyOn(jQuery, 'ajax').and.callThrough();
+ spyOn(axios, 'get').and.callThrough();
// eslint-disable-next-line no-new
new Job();
setTimeout(() => {
- expect(jQuery.ajax).toHaveBeenCalledWith(
- { url: `${JOB_URL}/trace.json`, data: { state: '' } },
+ expect(axios.get).toHaveBeenCalledWith(
+ `${JOB_URL}/trace.json`, { params: { state: '' } },
);
done();
}, 0);
diff --git a/spec/javascripts/jobs/job_details_mediator_spec.js b/spec/javascripts/jobs/job_details_mediator_spec.js
index 3069a0cd60e..ca5c9cf87e4 100644
--- a/spec/javascripts/jobs/job_details_mediator_spec.js
+++ b/spec/javascripts/jobs/job_details_mediator_spec.js
@@ -12,6 +12,10 @@ describe('JobMediator', () => {
mock = new MockAdapter(axios);
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('should set defaults', () => {
expect(mediator.store).toBeDefined();
expect(mediator.service).toBeDefined();
@@ -24,10 +28,6 @@ describe('JobMediator', () => {
mock.onGet().reply(200, job, {});
});
- afterEach(() => {
- mock.restore();
- });
-
it('should store received data', (done) => {
mediator.fetchJob();
setTimeout(() => {
diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js
index 43532275121..43589d54be4 100644
--- a/spec/javascripts/jobs/mock_data.js
+++ b/spec/javascripts/jobs/mock_data.js
@@ -37,7 +37,7 @@ export default {
username: 'root',
id: 1,
state: 'active',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
erase_path: '/root/ci-mock/-/jobs/4757/erase',
@@ -54,7 +54,7 @@ export default {
username: 'root',
id: 1,
state: 'active',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
active: false,
@@ -107,10 +107,10 @@ export default {
username: 'root',
id: 1,
state: 'active',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
- author_gravatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ author_gravatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
commit_url: 'http://localhost:3000/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
commit_path: '/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
},
diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js
index a197b35f6fb..7d992f62f64 100644
--- a/spec/javascripts/labels_issue_sidebar_spec.js
+++ b/spec/javascripts/labels_issue_sidebar_spec.js
@@ -1,4 +1,6 @@
/* eslint-disable no-new */
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import IssuableContext from '~/issuable_context';
import LabelsSelect from '~/labels_select';
@@ -10,35 +12,44 @@ import '~/users_select';
(() => {
let saveLabelCount = 0;
+ let mock;
+
describe('Issue dropdown sidebar', () => {
preloadFixtures('static/issue_sidebar_label.html.raw');
beforeEach(() => {
loadFixtures('static/issue_sidebar_label.html.raw');
+
+ mock = new MockAdapter(axios);
+
new IssuableContext('{"id":1,"name":"Administrator","username":"root"}');
new LabelsSelect();
- spyOn(jQuery, 'ajax').and.callFake((req) => {
- const d = $.Deferred();
- let LABELS_DATA = [];
+ mock.onGet('/root/test/labels.json').reply(() => {
+ const labels = Array(10).fill().map((_, i) => ({
+ id: i,
+ title: `test ${i}`,
+ color: '#5CB85C',
+ }));
- if (req.url === '/root/test/labels.json') {
- for (let i = 0; i < 10; i += 1) {
- LABELS_DATA.push({ id: i, title: `test ${i}`, color: '#5CB85C' });
- }
- } else if (req.url === '/root/test/issues/2.json') {
- const tmp = [];
- for (let i = 0; i < saveLabelCount; i += 1) {
- tmp.push({ id: i, title: `test ${i}`, color: '#5CB85C' });
- }
- LABELS_DATA = { labels: tmp };
- }
+ return [200, labels];
+ });
+
+ mock.onPut('/root/test/issues/2.json').reply(() => {
+ const labels = Array(saveLabelCount).fill().map((_, i) => ({
+ id: i,
+ title: `test ${i}`,
+ color: '#5CB85C',
+ }));
- d.resolve(LABELS_DATA);
- return d.promise();
+ return [200, { labels }];
});
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('changes collapsed tooltip when changing labels when less than 5', (done) => {
saveLabelCount = 5;
$('.edit-link').get(0).click();
diff --git a/spec/javascripts/lib/utils/ajax_cache_spec.js b/spec/javascripts/lib/utils/ajax_cache_spec.js
index 49971bd91e2..7603400b55e 100644
--- a/spec/javascripts/lib/utils/ajax_cache_spec.js
+++ b/spec/javascripts/lib/utils/ajax_cache_spec.js
@@ -1,3 +1,5 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import AjaxCache from '~/lib/utils/ajax_cache';
describe('AjaxCache', () => {
@@ -87,66 +89,53 @@ describe('AjaxCache', () => {
});
describe('retrieve', () => {
- let ajaxSpy;
+ let mock;
beforeEach(() => {
- spyOn(jQuery, 'ajax').and.callFake(url => ajaxSpy(url));
+ mock = new MockAdapter(axios);
+
+ spyOn(axios, 'get').and.callThrough();
+ });
+
+ afterEach(() => {
+ mock.restore();
});
it('stores and returns data from Ajax call if cache is empty', (done) => {
- ajaxSpy = (url) => {
- expect(url).toBe(dummyEndpoint);
- const deferred = $.Deferred();
- deferred.resolve(dummyResponse);
- return deferred.promise();
- };
+ mock.onGet(dummyEndpoint).reply(200, dummyResponse);
AjaxCache.retrieve(dummyEndpoint)
.then((data) => {
- expect(data).toBe(dummyResponse);
- expect(AjaxCache.internalStorage[dummyEndpoint]).toBe(dummyResponse);
+ expect(data).toEqual(dummyResponse);
+ expect(AjaxCache.internalStorage[dummyEndpoint]).toEqual(dummyResponse);
})
.then(done)
.catch(fail);
});
- it('makes no Ajax call if request is pending', () => {
- const responseDeferred = $.Deferred();
-
- ajaxSpy = (url) => {
- expect(url).toBe(dummyEndpoint);
- // neither reject nor resolve to keep request pending
- return responseDeferred.promise();
- };
-
- const unexpectedResponse = data => fail(`Did not expect response: ${data}`);
+ it('makes no Ajax call if request is pending', (done) => {
+ mock.onGet(dummyEndpoint).reply(200, dummyResponse);
AjaxCache.retrieve(dummyEndpoint)
- .then(unexpectedResponse)
+ .then(done)
.catch(fail);
AjaxCache.retrieve(dummyEndpoint)
- .then(unexpectedResponse)
+ .then(done)
.catch(fail);
- expect($.ajax.calls.count()).toBe(1);
+ expect(axios.get.calls.count()).toBe(1);
});
it('returns undefined if Ajax call fails and cache is empty', (done) => {
- const dummyStatusText = 'exploded';
- const dummyErrorMessage = 'server exploded';
- ajaxSpy = (url) => {
- expect(url).toBe(dummyEndpoint);
- const deferred = $.Deferred();
- deferred.reject(null, dummyStatusText, dummyErrorMessage);
- return deferred.promise();
- };
+ const errorMessage = 'Network Error';
+ mock.onGet(dummyEndpoint).networkError();
AjaxCache.retrieve(dummyEndpoint)
.then(data => fail(`Received unexpected data: ${JSON.stringify(data)}`))
.catch((error) => {
- expect(error.message).toBe(`${dummyEndpoint}: ${dummyErrorMessage}`);
- expect(error.textStatus).toBe(dummyStatusText);
+ expect(error.message).toBe(`${dummyEndpoint}: ${errorMessage}`);
+ expect(error.textStatus).toBe(errorMessage);
done();
})
.catch(fail);
@@ -154,7 +143,9 @@ describe('AjaxCache', () => {
it('makes no Ajax call if matching data exists', (done) => {
AjaxCache.internalStorage[dummyEndpoint] = dummyResponse;
- ajaxSpy = () => fail(new Error('expected no Ajax call!'));
+ mock.onGet(dummyEndpoint).reply(() => {
+ fail(new Error('expected no Ajax call!'));
+ });
AjaxCache.retrieve(dummyEndpoint)
.then((data) => {
@@ -171,12 +162,7 @@ describe('AjaxCache', () => {
AjaxCache.internalStorage[dummyEndpoint] = oldDummyResponse;
- ajaxSpy = (url) => {
- expect(url).toBe(dummyEndpoint);
- const deferred = $.Deferred();
- deferred.resolve(dummyResponse);
- return deferred.promise();
- };
+ mock.onGet(dummyEndpoint).reply(200, dummyResponse);
// Call without forceRetrieve param
AjaxCache.retrieve(dummyEndpoint)
@@ -189,7 +175,7 @@ describe('AjaxCache', () => {
// Call with forceRetrieve param
AjaxCache.retrieve(dummyEndpoint, true)
.then((data) => {
- expect(data).toBe(dummyResponse);
+ expect(data).toEqual(dummyResponse);
})
.then(done)
.catch(fail);
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 0a9d815f469..80430011aed 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -1,6 +1,7 @@
/* eslint-disable promise/catch-or-return */
-
+import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
+import MockAdapter from 'axios-mock-adapter';
describe('common_utils', () => {
describe('parseUrl', () => {
@@ -413,48 +414,48 @@ describe('common_utils', () => {
describe('setCiStatusFavicon', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`;
+ let mock;
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
document.body.appendChild(favicon);
+ mock = new MockAdapter(axios);
});
afterEach(() => {
+ mock.restore();
document.body.removeChild(document.getElementById('favicon'));
});
- it('should reset favicon in case of error', () => {
- const favicon = document.getElementById('favicon');
- spyOn($, 'ajax').and.callFake(function (options) {
- options.error();
- expect(favicon.getAttribute('href')).toEqual('null');
- });
+ it('should reset favicon in case of error', (done) => {
+ mock.onGet(BUILD_URL).networkError();
- commonUtils.setCiStatusFavicon(BUILD_URL);
+ commonUtils.setCiStatusFavicon(BUILD_URL)
+ .then(() => {
+ const favicon = document.getElementById('favicon');
+ expect(favicon.getAttribute('href')).toEqual('null');
+ done();
+ })
+ // Error is already caught in catch() block of setCiStatusFavicon,
+ // It won't throw another error for us to catch
+ .catch(done.fail);
});
- it('should set page favicon to CI status favicon based on provided status', () => {
+ it('should set page favicon to CI status favicon based on provided status', (done) => {
const FAVICON_PATH = '//icon_status_success';
- const favicon = document.getElementById('favicon');
- spyOn($, 'ajax').and.callFake(function (options) {
- options.success({ favicon: FAVICON_PATH });
- expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH);
+ mock.onGet(BUILD_URL).reply(200, {
+ favicon: FAVICON_PATH,
});
- commonUtils.setCiStatusFavicon(BUILD_URL);
- });
- });
-
- describe('ajaxPost', () => {
- it('should perform `$.ajax` call and do `POST` request', () => {
- const requestURL = '/some/random/api';
- const data = { keyname: 'value' };
- const ajaxSpy = spyOn($, 'ajax').and.callFake(() => {});
-
- commonUtils.ajaxPost(requestURL, data);
- expect(ajaxSpy.calls.allArgs()[0][0].type).toEqual('POST');
+ commonUtils.setCiStatusFavicon(BUILD_URL)
+ .then(() => {
+ const favicon = document.getElementById('favicon');
+ expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH);
+ done();
+ })
+ .catch(done.fail);
});
});
diff --git a/spec/javascripts/lib/utils/users_cache_spec.js b/spec/javascripts/lib/utils/users_cache_spec.js
index ec6ea35952b..50371c8c5f6 100644
--- a/spec/javascripts/lib/utils/users_cache_spec.js
+++ b/spec/javascripts/lib/utils/users_cache_spec.js
@@ -92,7 +92,9 @@ describe('UsersCache', () => {
apiSpy = (query, options) => {
expect(query).toBe('');
expect(options).toEqual({ username: dummyUsername });
- return Promise.resolve([dummyUser]);
+ return Promise.resolve({
+ data: [dummyUser],
+ });
};
UsersCache.retrieve(dummyUsername)
diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js
index bae3219b043..bdfd16ac995 100644
--- a/spec/javascripts/merge_request_spec.js
+++ b/spec/javascripts/merge_request_spec.js
@@ -1,5 +1,6 @@
/* eslint-disable space-before-function-paren, no-return-assign */
-
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import MergeRequest from '~/merge_request';
import CloseReopenReportToggle from '~/close_reopen_report_toggle';
import IssuablesHelper from '~/helpers/issuables_helper';
@@ -7,11 +8,24 @@ import IssuablesHelper from '~/helpers/issuables_helper';
(function() {
describe('MergeRequest', function() {
describe('task lists', function() {
+ let mock;
+
preloadFixtures('merge_requests/merge_request_with_task_list.html.raw');
beforeEach(function() {
loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
+
+ spyOn(axios, 'patch').and.callThrough();
+ mock = new MockAdapter(axios);
+
+ mock.onPatch(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`).reply(200, {});
+
return this.merge = new MergeRequest();
});
+
+ afterEach(() => {
+ mock.restore();
+ });
+
it('modifies the Markdown field', function() {
spyOn(jQuery, 'ajax').and.stub();
const changeEvent = document.createEvent('HTMLEvents');
@@ -21,14 +35,14 @@ import IssuablesHelper from '~/helpers/issuables_helper';
});
it('submits an ajax request on tasklist:changed', (done) => {
- spyOn(jQuery, 'ajax').and.callFake((req) => {
- expect(req.type).toBe('PATCH');
- expect(req.url).toBe(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`);
- expect(req.data.merge_request.description).not.toBe(null);
+ $('.js-task-list-field').trigger('tasklist:changed');
+
+ setTimeout(() => {
+ expect(axios.patch).toHaveBeenCalledWith(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`, {
+ merge_request: { description: '- [ ] Task List Item' },
+ });
done();
});
-
- $('.js-task-list-field').trigger('tasklist:changed');
});
});
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index a6be474805b..fda24db98b4 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -1,5 +1,6 @@
/* eslint-disable no-var, comma-dangle, object-shorthand */
-
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import MergeRequestTabs from '~/merge_request_tabs';
import '~/commit/pipelines/pipelines_bundle';
@@ -46,7 +47,7 @@ import 'vendor/jquery.scrollTo';
describe('activateTab', function () {
beforeEach(function () {
- spyOn($, 'ajax').and.callFake(function () {});
+ spyOn(axios, 'get').and.returnValue(Promise.resolve({ data: {} }));
loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
this.subject = this.class.activateTab;
});
@@ -148,7 +149,7 @@ import 'vendor/jquery.scrollTo';
describe('setCurrentAction', function () {
beforeEach(function () {
- spyOn($, 'ajax').and.callFake(function () {});
+ spyOn(axios, 'get').and.returnValue(Promise.resolve({ data: {} }));
this.subject = this.class.setCurrentAction;
});
@@ -214,13 +215,21 @@ import 'vendor/jquery.scrollTo';
});
describe('tabShown', () => {
+ let mock;
+
beforeEach(function () {
- spyOn($, 'ajax').and.callFake(function (options) {
- options.success({ html: '' });
+ mock = new MockAdapter(axios);
+ mock.onGet(/(.*)\/diffs\.json/).reply(200, {
+ data: { html: '' },
});
+
loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
});
+ afterEach(() => {
+ mock.restore();
+ });
+
describe('with "Side-by-side"/parallel diff view', () => {
beforeEach(function () {
this.class.diffViewType = () => 'parallel';
@@ -292,16 +301,20 @@ import 'vendor/jquery.scrollTo';
it('triggers Ajax request to JSON endpoint', function (done) {
const url = '/foo/bar/merge_requests/1/diffs';
- spyOn(this.class, 'ajaxGet').and.callFake((options) => {
- expect(options.url).toEqual(`${url}.json`);
+
+ spyOn(axios, 'get').and.callFake((reqUrl) => {
+ expect(reqUrl).toBe(`${url}.json`);
+
done();
+
+ return Promise.resolve({ data: {} });
});
this.class.loadDiff(url);
});
it('triggers scroll event when diff already loaded', function (done) {
- spyOn(this.class, 'ajaxGet').and.callFake(() => done.fail());
+ spyOn(axios, 'get').and.callFake(done.fail);
spyOn(document, 'dispatchEvent');
this.class.diffsLoaded = true;
@@ -316,6 +329,7 @@ import 'vendor/jquery.scrollTo';
describe('with inline diff', () => {
let noteId;
let noteLineNumId;
+ let mock;
beforeEach(() => {
const diffsResponse = getJSONFixture(inlineChangesTabJsonFixture);
@@ -330,29 +344,40 @@ import 'vendor/jquery.scrollTo';
.attr('href')
.replace('#', '');
- spyOn($, 'ajax').and.callFake(function (options) {
- options.success(diffsResponse);
- });
+ mock = new MockAdapter(axios);
+ mock.onGet(/(.*)\/diffs\.json/).reply(200, diffsResponse);
+ });
+
+ afterEach(() => {
+ mock.restore();
});
describe('with note fragment hash', () => {
- it('should expand and scroll to linked fragment hash #note_xxx', function () {
+ it('should expand and scroll to linked fragment hash #note_xxx', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId);
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(noteId.length).toBeGreaterThan(0);
- expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
- target: jasmine.any(Object),
- lineType: 'old',
- forceShow: true,
+ setTimeout(() => {
+ expect(noteId.length).toBeGreaterThan(0);
+ expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
+ target: jasmine.any(Object),
+ lineType: 'old',
+ forceShow: true,
+ });
+
+ done();
});
});
- it('should gracefully ignore non-existant fragment hash', function () {
+ it('should gracefully ignore non-existant fragment hash', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
+ setTimeout(() => {
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
+
+ done();
+ });
});
});
@@ -370,6 +395,7 @@ import 'vendor/jquery.scrollTo';
describe('with parallel diff', () => {
let noteId;
let noteLineNumId;
+ let mock;
beforeEach(() => {
const diffsResponse = getJSONFixture(parallelChangesTabJsonFixture);
@@ -384,30 +410,40 @@ import 'vendor/jquery.scrollTo';
.attr('href')
.replace('#', '');
- spyOn($, 'ajax').and.callFake(function (options) {
- options.success(diffsResponse);
- });
+ mock = new MockAdapter(axios);
+ mock.onGet(/(.*)\/diffs\.json/).reply(200, diffsResponse);
+ });
+
+ afterEach(() => {
+ mock.restore();
});
describe('with note fragment hash', () => {
- it('should expand and scroll to linked fragment hash #note_xxx', function () {
+ it('should expand and scroll to linked fragment hash #note_xxx', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId);
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(noteId.length).toBeGreaterThan(0);
- expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
- target: jasmine.any(Object),
- lineType: 'new',
- forceShow: true,
+ setTimeout(() => {
+ expect(noteId.length).toBeGreaterThan(0);
+ expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
+ target: jasmine.any(Object),
+ lineType: 'new',
+ forceShow: true,
+ });
+
+ done();
});
});
- it('should gracefully ignore non-existant fragment hash', function () {
+ it('should gracefully ignore non-existant fragment hash', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
+ setTimeout(() => {
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
+ done();
+ });
});
});
diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js
index 481b46c3ac6..6fa6f44f953 100644
--- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js
+++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js
@@ -1,7 +1,9 @@
/* eslint-disable no-new */
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
-import '~/flash';
+import timeoutPromise from './helpers/set_timeout_promise_helper';
describe('Mini Pipeline Graph Dropdown', () => {
preloadFixtures('static/mini_dropdown_graph.html.raw');
@@ -27,6 +29,16 @@ describe('Mini Pipeline Graph Dropdown', () => {
});
describe('When dropdown is clicked', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
it('should call getBuildsList', () => {
const getBuildsListSpy = spyOn(
MiniPipelineGraph.prototype,
@@ -41,46 +53,55 @@ describe('Mini Pipeline Graph Dropdown', () => {
});
it('should make a request to the endpoint provided in the html', () => {
- const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {});
+ const ajaxSpy = spyOn(axios, 'get').and.callThrough();
+
+ mock.onGet('foobar').reply(200, {
+ html: '',
+ });
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
- expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar');
+ expect(ajaxSpy.calls.allArgs()[0][0]).toEqual('foobar');
});
- it('should not close when user uses cmd/ctrl + click', () => {
- spyOn($, 'ajax').and.callFake(function (params) {
- params.success({
- html: `<li>
- <a class="mini-pipeline-graph-dropdown-item" href="#">
- <span class="ci-status-icon ci-status-icon-failed"></span>
- <span class="ci-build-text">build</span>
- </a>
- <a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
- </li>`,
- });
+ it('should not close when user uses cmd/ctrl + click', (done) => {
+ mock.onGet('foobar').reply(200, {
+ html: `<li>
+ <a class="mini-pipeline-graph-dropdown-item" href="#">
+ <span class="ci-status-icon ci-status-icon-failed"></span>
+ <span class="ci-build-text">build</span>
+ </a>
+ <a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
+ </li>`,
});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
- document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
-
- expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
+ timeoutPromise()
+ .then(() => {
+ document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
+ })
+ .then(timeoutPromise)
+ .then(() => {
+ expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
+ })
+ .then(done)
+ .catch(done.fail);
});
- });
- it('should close the dropdown when request returns an error', (done) => {
- spyOn($, 'ajax').and.callFake(options => options.error());
+ it('should close the dropdown when request returns an error', (done) => {
+ mock.onGet('foobar').networkError();
- new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
+ new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
- document.querySelector('.js-builds-dropdown-button').click();
+ document.querySelector('.js-builds-dropdown-button').click();
- setTimeout(() => {
- expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
- done();
- }, 0);
+ setTimeout(() => {
+ expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
+ done();
+ });
+ });
});
});
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index 9885b8a790f..eb8f6bbe50d 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -38,7 +38,7 @@ describe('Dashboard', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('shows up a loading state', (done) => {
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index b020a1020df..f0c800c759d 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -107,7 +107,7 @@ export const note = {
"name": "Administrator",
"username": "root",
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"path": "/root"
},
"created_at": "2017-08-10T15:24:03.087Z",
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index a40821a5693..274d7591c71 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -1,11 +1,14 @@
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
import _ from 'underscore';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
import '~/render_gfm';
import Notes from '~/notes';
+import timeoutPromise from './helpers/set_timeout_promise_helper';
(function() {
window.gon || (window.gon = {});
@@ -47,13 +50,24 @@ import Notes from '~/notes';
});
describe('task lists', function() {
+ let mock;
+
beforeEach(function() {
+ spyOn(axios, 'patch').and.callThrough();
+ mock = new MockAdapter(axios);
+
+ mock.onPatch(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`).reply(200, {});
+
$('.js-comment-button').on('click', function(e) {
e.preventDefault();
});
this.notes = new Notes('', []);
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('modifies the Markdown field', function() {
const changeEvent = document.createEvent('HTMLEvents');
changeEvent.initEvent('change', true, true);
@@ -62,14 +76,15 @@ import Notes from '~/notes';
expect($('.js-task-list-field.original-task-list').val()).toBe('- [x] Task List Item');
});
- it('submits an ajax request on tasklist:changed', function() {
- spyOn(jQuery, 'ajax').and.callFake(function(req) {
- expect(req.type).toBe('PATCH');
- expect(req.url).toBe('http://test.host/frontend-fixtures/merge-requests-project/merge_requests/1.json');
- return expect(req.data.note).not.toBe(null);
- });
+ it('submits an ajax request on tasklist:changed', function(done) {
+ $('.js-task-list-container').trigger('tasklist:changed');
- $('.js-task-list-field.js-note-text').trigger('tasklist:changed');
+ setTimeout(() => {
+ expect(axios.patch).toHaveBeenCalledWith(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`, {
+ note: { note: '' },
+ });
+ done();
+ });
});
});
@@ -119,6 +134,7 @@ import Notes from '~/notes';
let noteEntity;
let $form;
let $notesContainer;
+ let mock;
beforeEach(() => {
this.notes = new Notes('', []);
@@ -136,24 +152,32 @@ import Notes from '~/notes';
$form = $('form.js-main-target-form');
$notesContainer = $('ul.main-notes-list');
$form.find('textarea.js-note-text').val(sampleComment);
+
+ mock = new MockAdapter(axios);
+ mock.onPost(/(.*)\/notes$/).reply(200, noteEntity);
});
- it('updates note and resets edit form', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('updates note and resets edit form', (done) => {
spyOn(this.notes, 'revertNoteEditForm');
spyOn(this.notes, 'setupNewNote');
$('.js-comment-button').click();
- deferred.resolve(noteEntity);
- const $targetNote = $notesContainer.find(`#note_${noteEntity.id}`);
- const updatedNote = Object.assign({}, noteEntity);
- updatedNote.note = 'bar';
- this.notes.updateNote(updatedNote, $targetNote);
+ setTimeout(() => {
+ const $targetNote = $notesContainer.find(`#note_${noteEntity.id}`);
+ const updatedNote = Object.assign({}, noteEntity);
+ updatedNote.note = 'bar';
+ this.notes.updateNote(updatedNote, $targetNote);
+
+ expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
+ expect(this.notes.setupNewNote).toHaveBeenCalled();
- expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
- expect(this.notes.setupNewNote).toHaveBeenCalled();
+ done();
+ });
});
});
@@ -479,8 +503,19 @@ import Notes from '~/notes';
};
let $form;
let $notesContainer;
+ let mock;
+
+ function mockNotesPost() {
+ mock.onPost(/(.*)\/notes$/).reply(200, note);
+ }
+
+ function mockNotesPostError() {
+ mock.onPost(/(.*)\/notes$/).networkError();
+ }
beforeEach(() => {
+ mock = new MockAdapter(axios);
+
this.notes = new Notes('', []);
window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator';
@@ -489,63 +524,92 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').val(sampleComment);
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('should show placeholder note while new comment is being posted', () => {
+ mockNotesPost();
+
$('.js-comment-button').click();
expect($notesContainer.find('.note.being-posted').length > 0).toEqual(true);
});
- it('should remove placeholder note when new comment is done posting', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should remove placeholder note when new comment is done posting', (done) => {
+ mockNotesPost();
+
$('.js-comment-button').click();
- deferred.resolve(note);
- expect($notesContainer.find('.note.being-posted').length).toEqual(0);
+ setTimeout(() => {
+ expect($notesContainer.find('.note.being-posted').length).toEqual(0);
+
+ done();
+ });
});
- it('should show actual note element when new comment is done posting', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should show actual note element when new comment is done posting', (done) => {
+ mockNotesPost();
+
$('.js-comment-button').click();
- deferred.resolve(note);
- expect($notesContainer.find(`#note_${note.id}`).length > 0).toEqual(true);
+ setTimeout(() => {
+ expect($notesContainer.find(`#note_${note.id}`).length > 0).toEqual(true);
+
+ done();
+ });
});
- it('should reset Form when new comment is done posting', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should reset Form when new comment is done posting', (done) => {
+ mockNotesPost();
+
$('.js-comment-button').click();
- deferred.resolve(note);
- expect($form.find('textarea.js-note-text').val()).toEqual('');
+ setTimeout(() => {
+ expect($form.find('textarea.js-note-text').val()).toEqual('');
+
+ done();
+ });
});
- it('should show flash error message when new comment failed to be posted', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should show flash error message when new comment failed to be posted', (done) => {
+ mockNotesPostError();
+
$('.js-comment-button').click();
- deferred.reject();
- expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true);
+ setTimeout(() => {
+ expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true);
+
+ done();
+ });
});
- it('should show flash error message when comment failed to be updated', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ it('should show flash error message when comment failed to be updated', (done) => {
+ mockNotesPost();
+
$('.js-comment-button').click();
- deferred.resolve(note);
- const $noteEl = $notesContainer.find(`#note_${note.id}`);
- $noteEl.find('.js-note-edit').click();
- $noteEl.find('textarea.js-note-text').val(updatedComment);
- $noteEl.find('.js-comment-save-button').click();
+ timeoutPromise()
+ .then(() => {
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').val(updatedComment);
- deferred.reject();
- const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
- expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
- expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(sampleComment); // See if comment reverted back to original
- expect($('.flash-container').is(':visible')).toEqual(true); // Flash error message shown
+ mock.restore();
+
+ mockNotesPostError();
+
+ $noteEl.find('.js-comment-save-button').click();
+ })
+ .then(timeoutPromise)
+ .then(() => {
+ const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
+ expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
+ expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(sampleComment); // See if comment reverted back to original
+ expect($('.flash-container').is(':visible')).toEqual(true); // Flash error message shown
+
+ done();
+ })
+ .catch(done.fail);
});
});
@@ -563,8 +627,12 @@ import Notes from '~/notes';
};
let $form;
let $notesContainer;
+ let mock;
beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onPost(/(.*)\/notes$/).reply(200, note);
+
this.notes = new Notes('', []);
window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator';
@@ -582,15 +650,20 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').val(sampleComment);
});
- it('should remove slash command placeholder when comment with slash commands is done posting', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should remove slash command placeholder when comment with slash commands is done posting', (done) => {
spyOn(gl.awardsHandler, 'addAwardToEmojiBar').and.callThrough();
$('.js-comment-button').click();
expect($notesContainer.find('.system-note.being-posted').length).toEqual(1); // Placeholder shown
- deferred.resolve(note);
- expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed
+
+ setTimeout(() => {
+ expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed
+ done();
+ });
});
});
@@ -607,8 +680,12 @@ import Notes from '~/notes';
};
let $form;
let $notesContainer;
+ let mock;
beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onPost(/(.*)\/notes$/).reply(200, note);
+
this.notes = new Notes('', []);
window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator';
@@ -617,19 +694,24 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').html(sampleComment);
});
- it('should not render a script tag', () => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should not render a script tag', (done) => {
$('.js-comment-button').click();
- deferred.resolve(note);
- const $noteEl = $notesContainer.find(`#note_${note.id}`);
- $noteEl.find('.js-note-edit').click();
- $noteEl.find('textarea.js-note-text').html(updatedComment);
- $noteEl.find('.js-comment-save-button').click();
+ setTimeout(() => {
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').html(updatedComment);
+ $noteEl.find('.js-comment-save-button').click();
+
+ const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container');
+ expect($updatedNoteEl.find('.note-text').text().trim()).toEqual('');
- const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container');
- expect($updatedNoteEl.find('.note-text').text().trim()).toEqual('');
+ done();
+ });
});
});
diff --git a/spec/javascripts/pager_spec.js b/spec/javascripts/pager_spec.js
index 2fd87754238..b09494f0b77 100644
--- a/spec/javascripts/pager_spec.js
+++ b/spec/javascripts/pager_spec.js
@@ -1,5 +1,6 @@
/* global fixture */
-
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import * as utils from '~/lib/utils/url_utility';
import Pager from '~/pager';
@@ -9,7 +10,6 @@ describe('pager', () => {
beforeEach(() => {
setFixtures('<div class="content_list"></div><div class="loading"></div>');
- spyOn($, 'ajax');
});
afterEach(() => {
@@ -47,39 +47,90 @@ describe('pager', () => {
});
describe('getOld', () => {
+ const urlRegex = /(.*)some_list(.*)$/;
+ let mock;
+
+ function mockSuccess() {
+ mock.onGet(urlRegex).reply(200, {
+ count: 0,
+ html: '',
+ });
+ }
+
+ function mockError() {
+ mock.onGet(urlRegex).networkError();
+ }
+
beforeEach(() => {
setFixtures('<div class="content_list" data-href="/some_list"></div><div class="loading"></div>');
+ spyOn(axios, 'get').and.callThrough();
+
+ mock = new MockAdapter(axios);
+
Pager.init();
});
- it('shows loader while loading next page', () => {
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('shows loader while loading next page', (done) => {
+ mockSuccess();
+
spyOn(Pager.loading, 'show');
Pager.getOld();
- expect(Pager.loading.show).toHaveBeenCalled();
+
+ setTimeout(() => {
+ expect(Pager.loading.show).toHaveBeenCalled();
+
+ done();
+ });
});
- it('hides loader on success', () => {
- spyOn($, 'ajax').and.callFake(options => options.success({}));
+ it('hides loader on success', (done) => {
+ mockSuccess();
+
spyOn(Pager.loading, 'hide');
Pager.getOld();
- expect(Pager.loading.hide).toHaveBeenCalled();
+
+ setTimeout(() => {
+ expect(Pager.loading.hide).toHaveBeenCalled();
+
+ done();
+ });
});
- it('hides loader on error', () => {
- spyOn($, 'ajax').and.callFake(options => options.error());
+ it('hides loader on error', (done) => {
+ mockError();
+
spyOn(Pager.loading, 'hide');
Pager.getOld();
- expect(Pager.loading.hide).toHaveBeenCalled();
+
+ setTimeout(() => {
+ expect(Pager.loading.hide).toHaveBeenCalled();
+
+ done();
+ });
});
- it('sends request to url with offset and limit params', () => {
- spyOn($, 'ajax');
+ it('sends request to url with offset and limit params', (done) => {
Pager.offset = 100;
Pager.limit = 20;
Pager.getOld();
- const [{ data, url }] = $.ajax.calls.argsFor(0);
- expect(data).toBe('limit=20&offset=100');
- expect(url).toBe('/some_list');
+
+ setTimeout(() => {
+ const [url, params] = axios.get.calls.argsFor(0);
+
+ expect(params).toEqual({
+ params: {
+ limit: 20,
+ offset: 100,
+ },
+ });
+ expect(url).toBe('/some_list');
+
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js b/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js
new file mode 100644
index 00000000000..3cd33a3e900
--- /dev/null
+++ b/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js
@@ -0,0 +1,95 @@
+import Vue from 'vue';
+
+import axios from '~/lib/utils/axios_utils';
+import deleteMilestoneModal from '~/pages/milestones/shared/components/delete_milestone_modal.vue';
+import eventHub from '~/pages/milestones/shared/event_hub';
+import * as urlUtility from '~/lib/utils/url_utility';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+describe('delete_milestone_modal.vue', () => {
+ const Component = Vue.extend(deleteMilestoneModal);
+ const props = {
+ issueCount: 1,
+ mergeRequestCount: 2,
+ milestoneId: 3,
+ milestoneTitle: 'my milestone title',
+ milestoneUrl: `${gl.TEST_HOST}/delete_milestone_modal.vue/milestone`,
+ };
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('onSubmit', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ spyOn(eventHub, '$emit');
+ });
+
+ it('deletes milestone and redirects to overview page', (done) => {
+ const responseURL = `${gl.TEST_HOST}/delete_milestone_modal.vue/milestoneOverview`;
+ spyOn(axios, 'delete').and.callFake((url) => {
+ expect(url).toBe(props.milestoneUrl);
+ expect(eventHub.$emit).toHaveBeenCalledWith('deleteMilestoneModal.requestStarted', props.milestoneUrl);
+ eventHub.$emit.calls.reset();
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+ const redirectSpy = spyOn(urlUtility, 'redirectTo');
+
+ vm.onSubmit()
+ .then(() => {
+ expect(redirectSpy).toHaveBeenCalledWith(responseURL);
+ expect(eventHub.$emit).toHaveBeenCalledWith('deleteMilestoneModal.requestFinished', { milestoneUrl: props.milestoneUrl, successful: true });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays error if deleting milestone failed', (done) => {
+ const dummyError = new Error('deleting milestone failed');
+ dummyError.response = { status: 418 };
+ spyOn(axios, 'delete').and.callFake((url) => {
+ expect(url).toBe(props.milestoneUrl);
+ expect(eventHub.$emit).toHaveBeenCalledWith('deleteMilestoneModal.requestStarted', props.milestoneUrl);
+ eventHub.$emit.calls.reset();
+ return Promise.reject(dummyError);
+ });
+ const redirectSpy = spyOn(urlUtility, 'redirectTo');
+
+ vm.onSubmit()
+ .catch((error) => {
+ expect(error).toBe(dummyError);
+ expect(redirectSpy).not.toHaveBeenCalled();
+ expect(eventHub.$emit).toHaveBeenCalledWith('deleteMilestoneModal.requestFinished', { milestoneUrl: props.milestoneUrl, successful: false });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('text', () => {
+ it('contains the issue and milestone count', () => {
+ vm = mountComponent(Component, props);
+ const value = vm.text;
+
+ expect(value).toContain('remove it from 1 issue and 2 merge requests');
+ });
+
+ it('contains neither issue nor milestone count', () => {
+ vm = mountComponent(Component, { ...props,
+ issueCount: 0,
+ mergeRequestCount: 0,
+ });
+
+ const value = vm.text;
+
+ expect(value).toContain('is not currently used');
+ });
+ });
+});
diff --git a/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js b/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
deleted file mode 100644
index 5b316b319a5..00000000000
--- a/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import {
- setupPipelineVariableList,
- insertRow,
- removeRow,
-} from '~/pipeline_schedules/setup_pipeline_variable_list';
-
-describe('Pipeline Variable List', () => {
- let $markup;
-
- describe('insertRow', () => {
- it('should insert another row', () => {
- $markup = $(`<div>
- <li class="js-row">
- <input>
- <textarea></textarea>
- </li>
- </div>`);
-
- insertRow($markup.find('.js-row'));
-
- expect($markup.find('.js-row').length).toBe(2);
- });
-
- it('should clear `data-is-persisted` on cloned row', () => {
- $markup = $(`<div>
- <li class="js-row" data-is-persisted="true"></li>
- </div>`);
-
- insertRow($markup.find('.js-row'));
-
- const $lastRow = $markup.find('.js-row').last();
- expect($lastRow.attr('data-is-persisted')).toBe(undefined);
- });
-
- it('should clear inputs on cloned row', () => {
- $markup = $(`<div>
- <li class="js-row">
- <input value="foo">
- <textarea>bar</textarea>
- </li>
- </div>`);
-
- insertRow($markup.find('.js-row'));
-
- const $lastRow = $markup.find('.js-row').last();
- expect($lastRow.find('input').val()).toBe('');
- expect($lastRow.find('textarea').val()).toBe('');
- });
- });
-
- describe('removeRow', () => {
- it('should remove dynamic row', () => {
- $markup = $(`<div>
- <li class="js-row">
- <input>
- <textarea></textarea>
- </li>
- </div>`);
-
- removeRow($markup.find('.js-row'));
-
- expect($markup.find('.js-row').length).toBe(0);
- });
-
- it('should hide and mark to destroy with already persisted rows', () => {
- $markup = $(`<div>
- <li class="js-row" data-is-persisted="true">
- <input class="js-destroy-input">
- </li>
- </div>`);
-
- const $row = $markup.find('.js-row');
- removeRow($row);
-
- expect($row.find('.js-destroy-input').val()).toBe('1');
- expect($markup.find('.js-row').length).toBe(1);
- });
- });
-
- describe('setupPipelineVariableList', () => {
- beforeEach(() => {
- $markup = $(`<form>
- <li class="js-row">
- <input class="js-user-input" name="schedule[variables_attributes][][key]">
- <textarea class="js-user-input" name="schedule[variables_attributes][][value]"></textarea>
- <button class="js-row-remove-button"></button>
- <button class="js-row-add-button"></button>
- </li>
- </form>`);
-
- setupPipelineVariableList($markup);
- });
-
- it('should remove the row when clicking the remove button', () => {
- $markup.find('.js-row-remove-button').trigger('click');
-
- expect($markup.find('.js-row').length).toBe(0);
- });
-
- it('should add another row when editing the last rows key input', () => {
- const $row = $markup.find('.js-row');
- $row.find('input.js-user-input')
- .val('foo')
- .trigger('input');
-
- expect($markup.find('.js-row').length).toBe(2);
- });
-
- it('should add another row when editing the last rows value textarea', () => {
- const $row = $markup.find('.js-row');
- $row.find('textarea.js-user-input')
- .val('foo')
- .trigger('input');
-
- expect($markup.find('.js-row').length).toBe(2);
- });
-
- it('should remove empty row after blurring', () => {
- const $row = $markup.find('.js-row');
- $row.find('input.js-user-input')
- .val('foo')
- .trigger('input');
-
- expect($markup.find('.js-row').length).toBe(2);
-
- $row.find('input.js-user-input')
- .val('')
- .trigger('input')
- .trigger('blur');
-
- expect($markup.find('.js-row').length).toBe(1);
- });
-
- it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => {
- const $row = $markup.find('.js-row');
- expect($row.find('input').attr('name')).toBe('schedule[variables_attributes][][key]');
- expect($row.find('textarea').attr('name')).toBe('schedule[variables_attributes][][value]');
-
- $markup.filter('form').submit();
-
- expect($row.find('input').attr('name')).toBe('');
- expect($row.find('textarea').attr('name')).toBe('');
- });
- });
-});
diff --git a/spec/javascripts/pipelines/pipelines_table_row_spec.js b/spec/javascripts/pipelines/pipelines_table_row_spec.js
index a9126d2f4e9..de744739e42 100644
--- a/spec/javascripts/pipelines/pipelines_table_row_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_row_spec.js
@@ -24,9 +24,10 @@ describe('Pipelines Table Row', () => {
beforeEach(() => {
const pipelines = getJSONFixture(jsonFixtureName).pipelines;
- pipeline = pipelines.find(p => p.id === 1);
- pipelineWithoutAuthor = pipelines.find(p => p.id === 2);
- pipelineWithoutCommit = pipelines.find(p => p.id === 3);
+
+ pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
+ pipelineWithoutAuthor = pipelines.find(p => p.user === null && p.commit !== null);
+ pipelineWithoutCommit = pipelines.find(p => p.user === null && p.commit === null);
});
afterEach(() => {
diff --git a/spec/javascripts/pipelines/pipelines_table_spec.js b/spec/javascripts/pipelines/pipelines_table_spec.js
index ca2f9163313..4fc3c08145e 100644
--- a/spec/javascripts/pipelines/pipelines_table_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_spec.js
@@ -11,9 +11,10 @@ describe('Pipelines Table', () => {
preloadFixtures(jsonFixtureName);
beforeEach(() => {
- PipelinesTableComponent = Vue.extend(pipelinesTableComp);
const pipelines = getJSONFixture(jsonFixtureName).pipelines;
- pipeline = pipelines.find(p => p.id === 1);
+
+ PipelinesTableComponent = Vue.extend(pipelinesTableComp);
+ pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
});
describe('table', () => {
diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
index b24567ffc0c..f6c0f51cf62 100644
--- a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
+++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
@@ -1,3 +1,5 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import PrometheusMetrics from '~/prometheus_metrics/prometheus_metrics';
import PANEL_STATE from '~/prometheus_metrics/constants';
import { metrics, missingVarMetrics } from './mock_data';
@@ -102,25 +104,38 @@ describe('PrometheusMetrics', () => {
describe('loadActiveMetrics', () => {
let prometheusMetrics;
+ let mock;
+
+ function mockSuccess() {
+ mock.onGet(prometheusMetrics.activeMetricsEndpoint).reply(200, {
+ data: metrics,
+ success: true,
+ });
+ }
+
+ function mockError() {
+ mock.onGet(prometheusMetrics.activeMetricsEndpoint).networkError();
+ }
beforeEach(() => {
+ spyOn(axios, 'get').and.callThrough();
+
prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
+
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
});
it('should show loader animation while response is being loaded and hide it when request is complete', (done) => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
+ mockSuccess();
prometheusMetrics.loadActiveMetrics();
expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeFalsy();
- expect($.ajax).toHaveBeenCalledWith({
- url: prometheusMetrics.activeMetricsEndpoint,
- dataType: 'json',
- global: false,
- });
-
- deferred.resolve({ data: metrics, success: true });
+ expect(axios.get).toHaveBeenCalledWith(prometheusMetrics.activeMetricsEndpoint);
setTimeout(() => {
expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
@@ -129,14 +144,10 @@ describe('PrometheusMetrics', () => {
});
it('should show empty state if response failed to load', (done) => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- spyOn(prometheusMetrics, 'populateActiveMetrics');
+ mockError();
prometheusMetrics.loadActiveMetrics();
- deferred.reject();
-
setTimeout(() => {
expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeFalsy();
@@ -145,14 +156,11 @@ describe('PrometheusMetrics', () => {
});
it('should populate metrics list once response is loaded', (done) => {
- const deferred = $.Deferred();
- spyOn($, 'ajax').and.returnValue(deferred.promise());
spyOn(prometheusMetrics, 'populateActiveMetrics');
+ mockSuccess();
prometheusMetrics.loadActiveMetrics();
- deferred.resolve({ data: metrics, success: true });
-
setTimeout(() => {
expect(prometheusMetrics.populateActiveMetrics).toHaveBeenCalledWith(metrics);
done();
diff --git a/spec/javascripts/repo/components/new_dropdown/modal_spec.js b/spec/javascripts/repo/components/new_dropdown/modal_spec.js
index 233cca06ed0..8bbc3100357 100644
--- a/spec/javascripts/repo/components/new_dropdown/modal_spec.js
+++ b/spec/javascripts/repo/components/new_dropdown/modal_spec.js
@@ -18,8 +18,10 @@ describe('new file modal component', () => {
}));
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
- commit: {
- id: '123branch',
+ data: {
+ commit: {
+ id: '123branch',
+ },
},
}));
diff --git a/spec/javascripts/repo/components/new_dropdown/upload_spec.js b/spec/javascripts/repo/components/new_dropdown/upload_spec.js
index 788c08e5279..667112ab21a 100644
--- a/spec/javascripts/repo/components/new_dropdown/upload_spec.js
+++ b/spec/javascripts/repo/components/new_dropdown/upload_spec.js
@@ -17,8 +17,10 @@ describe('new dropdown upload', () => {
}));
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
- commit: {
- id: '123branch',
+ data: {
+ commit: {
+ id: '123branch',
+ },
},
}));
diff --git a/spec/javascripts/repo/components/repo_commit_section_spec.js b/spec/javascripts/repo/components/repo_commit_section_spec.js
index 676ac09f2c9..93e94b4f24c 100644
--- a/spec/javascripts/repo/components/repo_commit_section_spec.js
+++ b/spec/javascripts/repo/components/repo_commit_section_spec.js
@@ -87,8 +87,10 @@ describe('RepoCommitSection', () => {
changedFiles = JSON.parse(JSON.stringify(vm.$store.getters.changedFiles));
spyOn(service, 'commit').and.returnValue(Promise.resolve({
- short_id: '1',
- stats: {},
+ data: {
+ short_id: '1',
+ stats: {},
+ },
}));
});
diff --git a/spec/javascripts/repo/stores/actions_spec.js b/spec/javascripts/repo/stores/actions_spec.js
index 8d830c67290..f678967b092 100644
--- a/spec/javascripts/repo/stores/actions_spec.js
+++ b/spec/javascripts/repo/stores/actions_spec.js
@@ -178,7 +178,9 @@ describe('Multi-file store actions', () => {
it('calls service', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
- commit: { id: '123' },
+ data: {
+ commit: { id: '123' },
+ },
}));
store.dispatch('checkCommitStatus')
@@ -192,7 +194,9 @@ describe('Multi-file store actions', () => {
it('returns true if current ref does not equal returned ID', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
- commit: { id: '123' },
+ data: {
+ commit: { id: '123' },
+ },
}));
store.dispatch('checkCommitStatus')
@@ -206,7 +210,9 @@ describe('Multi-file store actions', () => {
it('returns false if current ref equals returned ID', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
- commit: { id: '1' },
+ data: {
+ commit: { id: '1' },
+ },
}));
store.dispatch('checkCommitStatus')
@@ -250,13 +256,15 @@ describe('Multi-file store actions', () => {
describe('success', () => {
beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({
- id: '123456',
- short_id: '123',
- message: 'test message',
- committed_date: 'date',
- stats: {
- additions: '1',
- deletions: '2',
+ data: {
+ id: '123456',
+ short_id: '123',
+ message: 'test message',
+ committed_date: 'date',
+ stats: {
+ additions: '1',
+ deletions: '2',
+ },
},
}));
});
@@ -324,7 +332,9 @@ describe('Multi-file store actions', () => {
describe('failed', () => {
beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({
- message: 'failed message',
+ data: {
+ message: 'failed message',
+ },
}));
});
diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js
index 3267e29585b..35bb630bf5d 100644
--- a/spec/javascripts/right_sidebar_spec.js
+++ b/spec/javascripts/right_sidebar_spec.js
@@ -1,6 +1,8 @@
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */
+import MockAdapter from 'axios-mock-adapter';
import '~/commons/bootstrap';
+import axios from '~/lib/utils/axios_utils';
import Sidebar from '~/right_sidebar';
(function() {
@@ -35,16 +37,23 @@ import Sidebar from '~/right_sidebar';
var fixtureName = 'issues/open-issue.html.raw';
preloadFixtures(fixtureName);
loadJSONFixtures('todos/todos.json');
+ let mock;
beforeEach(function() {
loadFixtures(fixtureName);
- this.sidebar = new Sidebar;
+ mock = new MockAdapter(axios);
+ this.sidebar = new Sidebar();
$aside = $('.right-sidebar');
$page = $('.layout-page');
$icon = $aside.find('i');
$toggle = $aside.find('.js-sidebar-toggle');
return $labelsIcon = $aside.find('.sidebar-collapsed-icon');
});
+
+ afterEach(() => {
+ mock.restore();
+ });
+
it('should expand/collapse the sidebar when arrow is clicked', function() {
assertSidebarState('expanded');
$toggle.click();
@@ -63,20 +72,19 @@ import Sidebar from '~/right_sidebar';
return assertSidebarState('collapsed');
});
- it('should broadcast todo:toggle event when add todo clicked', function() {
+ it('should broadcast todo:toggle event when add todo clicked', function(done) {
var todos = getJSONFixture('todos/todos.json');
- spyOn(jQuery, 'ajax').and.callFake(function() {
- var d = $.Deferred();
- var response = todos;
- d.resolve(response);
- return d.promise();
- });
+ mock.onPost(/(.*)\/todos$/).reply(200, todos);
var todoToggleSpy = spyOnEvent(document, 'todo:toggle');
$('.issuable-sidebar-header .js-issuable-todo').click();
- expect(todoToggleSpy.calls.count()).toEqual(1);
+ setTimeout(() => {
+ expect(todoToggleSpy.calls.count()).toEqual(1);
+
+ done();
+ });
});
it('should not hide collapsed icons', () => {
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 7bc591d2d47..d9e84e35f69 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -27,7 +27,7 @@ const RESPONSE_MAP = {
username: 'user0',
id: 22,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/user0',
},
{
@@ -35,7 +35,7 @@ const RESPONSE_MAP = {
username: 'tajuana',
id: 18,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/tajuana',
},
{
@@ -43,7 +43,7 @@ const RESPONSE_MAP = {
username: 'michaele.will',
id: 16,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/michaele.will',
},
],
@@ -72,24 +72,24 @@ const RESPONSE_MAP = {
username: 'user0',
id: 22,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/user0',
+ avatar_url: 'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/tajuana',
+ avatar_url: 'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/michaele.will',
+ avatar_url: 'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/michaele.will',
},
],
human_time_estimate: null,
@@ -100,24 +100,24 @@ const RESPONSE_MAP = {
username: 'user0',
id: 22,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/user0',
+ avatar_url: 'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/tajuana',
+ avatar_url: 'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
- avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/michaele.will',
+ avatar_url: 'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3001/michaele.will',
},
],
subscribed: true,
@@ -182,7 +182,7 @@ const mockData = {
id: 1,
name: 'Administrator',
username: 'root',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
rootPath: '/',
fullPath: '/gitlab-org/gitlab-shell',
@@ -194,7 +194,7 @@ const mockData = {
human_total_time_spent: null,
},
user: {
- avatar: 'http://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'Administrator',
username: 'root',
diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js
index ea4eae1e23f..3591f96ff87 100644
--- a/spec/javascripts/sidebar/sidebar_store_spec.js
+++ b/spec/javascripts/sidebar/sidebar_store_spec.js
@@ -6,14 +6,14 @@ const ASSIGNEE = {
id: 2,
name: 'gitlab user 2',
username: 'gitlab2',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
};
const ANOTHER_ASSINEE = {
id: 3,
name: 'gitlab user 3',
username: 'gitlab3',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
};
const PARTICIPANT = {
@@ -38,7 +38,7 @@ describe('Sidebar store', () => {
id: 1,
name: 'Administrator',
username: 'root',
- avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
editable: true,
rootPath: '/',
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 2f6691df9cd..9b2a5379855 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -6,6 +6,8 @@ import '~/commons';
import Vue from 'vue';
import VueResource from 'vue-resource';
+import { getDefaultAdapter } from '~/lib/utils/axios_utils';
+
const isHeadlessChrome = /\bHeadlessChrome\//.test(navigator.userAgent);
Vue.config.devtools = !isHeadlessChrome;
Vue.config.productionTip = false;
@@ -59,6 +61,8 @@ beforeEach(() => {
Vue.http.interceptors = builtinVueHttpInterceptors.slice();
});
+const axiosDefaultAdapter = getDefaultAdapter();
+
// render all of our tests
const testsContext = require.context('.', true, /_spec$/);
testsContext.keys().forEach(function (path) {
@@ -94,6 +98,12 @@ describe('test errors', () => {
it('has no Vue error', () => {
expect(hasVueErrors).toBe(false);
});
+
+ it('restores axios adapter after mocking', () => {
+ if (getDefaultAdapter() !== axiosDefaultAdapter) {
+ fail('axios adapter is not restored! Did you forget a restore() on MockAdapter?');
+ }
+ });
});
// if we're generating coverage reports, make sure to include all files so
diff --git a/spec/javascripts/toggle_buttons_spec.js b/spec/javascripts/toggle_buttons_spec.js
new file mode 100644
index 00000000000..205e396d682
--- /dev/null
+++ b/spec/javascripts/toggle_buttons_spec.js
@@ -0,0 +1,120 @@
+import setupToggleButtons from '~/toggle_buttons';
+import getSetTimeoutPromise from './helpers/set_timeout_promise_helper';
+
+function generateMarkup(isChecked = true) {
+ return `
+ <button type="button" class="${isChecked ? 'is-checked' : ''} js-project-feature-toggle">
+ <input type="hidden" class="js-project-feature-toggle-input" value="${isChecked}" />
+ </button>
+ `;
+}
+
+function setupFixture(isChecked, clickCallback) {
+ const wrapper = document.createElement('div');
+ wrapper.innerHTML = generateMarkup(isChecked);
+
+ setupToggleButtons(wrapper, clickCallback);
+
+ return wrapper;
+}
+
+describe('ToggleButtons', () => {
+ describe('when input value is true', () => {
+ it('should initialize as checked', () => {
+ const wrapper = setupFixture(true);
+
+ expect(wrapper.querySelector('.js-project-feature-toggle').classList.contains('is-checked')).toEqual(true);
+ expect(wrapper.querySelector('.js-project-feature-toggle-input').value).toEqual('true');
+ });
+
+ it('should toggle to unchecked when clicked', (done) => {
+ const wrapper = setupFixture(true);
+ const toggleButton = wrapper.querySelector('.js-project-feature-toggle');
+
+ toggleButton.click();
+
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(toggleButton.classList.contains('is-checked')).toEqual(false);
+ expect(wrapper.querySelector('.js-project-feature-toggle-input').value).toEqual('false');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('when input value is false', () => {
+ it('should initialize as unchecked', () => {
+ const wrapper = setupFixture(false);
+
+ expect(wrapper.querySelector('.js-project-feature-toggle').classList.contains('is-checked')).toEqual(false);
+ expect(wrapper.querySelector('.js-project-feature-toggle-input').value).toEqual('false');
+ });
+
+ it('should toggle to checked when clicked', (done) => {
+ const wrapper = setupFixture(false);
+ const toggleButton = wrapper.querySelector('.js-project-feature-toggle');
+
+ toggleButton.click();
+
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(toggleButton.classList.contains('is-checked')).toEqual(true);
+ expect(wrapper.querySelector('.js-project-feature-toggle-input').value).toEqual('true');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ it('should emit `trigger-change` event', (done) => {
+ const changeSpy = jasmine.createSpy('changeEventHandler');
+ const wrapper = setupFixture(false);
+ const toggleButton = wrapper.querySelector('.js-project-feature-toggle');
+ const input = wrapper.querySelector('.js-project-feature-toggle-input');
+
+ $(input).on('trigger-change', changeSpy);
+
+ toggleButton.click();
+
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(changeSpy).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('clickCallback', () => {
+ it('should show loading indicator while waiting', (done) => {
+ const isChecked = true;
+ const clickCallback = (newValue, toggleButton) => {
+ const input = toggleButton.querySelector('.js-project-feature-toggle-input');
+
+ expect(newValue).toEqual(false);
+
+ // Check for the loading state
+ expect(toggleButton.classList.contains('is-checked')).toEqual(false);
+ expect(toggleButton.classList.contains('is-loading')).toEqual(true);
+ expect(toggleButton.disabled).toEqual(true);
+ expect(input.value).toEqual('true');
+
+ // After the callback finishes, check that the loading state is gone
+ getSetTimeoutPromise()
+ .then(() => {
+ expect(toggleButton.classList.contains('is-checked')).toEqual(false);
+ expect(toggleButton.classList.contains('is-loading')).toEqual(false);
+ expect(toggleButton.disabled).toEqual(false);
+ expect(input.value).toEqual('false');
+ })
+ .then(done)
+ .catch(done.fail);
+ };
+
+ const wrapper = setupFixture(isChecked, clickCallback);
+ const toggleButton = wrapper.querySelector('.js-project-feature-toggle');
+
+ toggleButton.click();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js
index a750bc78f36..f14d5f6f76c 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js
@@ -1,39 +1,39 @@
import Vue from 'vue';
-import authorComponent from '~/vue_merge_request_widget/components/mr_widget_author';
-
-const author = {
- webUrl: 'http://foo.bar',
- avatarUrl: 'http://gravatar.com/foo',
- name: 'fatihacet',
-};
-const createComponent = () => {
- const Component = Vue.extend(authorComponent);
-
- return new Component({
- el: document.createElement('div'),
- propsData: { author },
- });
-};
+import authorComponent from '~/vue_merge_request_widget/components/mr_widget_author.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetAuthor', () => {
- describe('props', () => {
- it('should have props', () => {
- const authorProp = authorComponent.props.author;
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(authorComponent);
+
+ vm = mountComponent(Component, {
+ author: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://localhost:3000/root',
+ avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
- expect(authorProp).toBeDefined();
- expect(authorProp.type instanceof Object).toBeTruthy();
- expect(authorProp.required).toBeTruthy();
});
});
- describe('template', () => {
- it('should have correct elements', () => {
- const el = createComponent().$el;
+ afterEach(() => {
+ vm.$destroy();
+ });
- expect(el.tagName).toEqual('A');
- expect(el.getAttribute('href')).toEqual(author.webUrl);
- expect(el.querySelector('img').getAttribute('src')).toEqual(author.avatarUrl);
- expect(el.querySelector('.author').innerText.trim()).toEqual(author.name);
- });
+ it('renders link with the author web url', () => {
+ expect(vm.$el.getAttribute('href')).toEqual('http://localhost:3000/root');
+ });
+
+ it('renders image with avatar url', () => {
+ expect(
+ vm.$el.querySelector('img').getAttribute('src'),
+ ).toEqual('http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon');
+ });
+
+ it('renders author name', () => {
+ expect(vm.$el.textContent.trim()).toEqual('Administrator');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js
index 515ddcbb875..8c55622b15e 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js
@@ -1,61 +1,40 @@
import Vue from 'vue';
-import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time';
-
-const props = {
- actionText: 'Merged by',
- author: {
- webUrl: 'http://foo.bar',
- avatarUrl: 'http://gravatar.com/foo',
- name: 'fatihacet',
- },
- dateTitle: '2017-03-23T23:02:00.807Z',
- dateReadable: '12 hours ago',
-};
-const createComponent = () => {
- const Component = Vue.extend(authorTimeComponent);
-
- return new Component({
- el: document.createElement('div'),
- propsData: props,
- });
-};
+import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetAuthorTime', () => {
- describe('props', () => {
- it('should have props', () => {
- const { actionText, author, dateTitle, dateReadable } = authorTimeComponent.props;
- const ActionTextClass = actionText.type;
- const DateTitleClass = dateTitle.type;
- const DateReadableClass = dateReadable.type;
-
- expect(new ActionTextClass() instanceof String).toBeTruthy();
- expect(actionText.required).toBeTruthy();
-
- expect(author.type instanceof Object).toBeTruthy();
- expect(author.required).toBeTruthy();
-
- expect(new DateTitleClass() instanceof String).toBeTruthy();
- expect(dateTitle.required).toBeTruthy();
-
- expect(new DateReadableClass() instanceof String).toBeTruthy();
- expect(dateReadable.required).toBeTruthy();
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(authorTimeComponent);
+
+ vm = mountComponent(Component, {
+ actionText: 'Merged by',
+ author: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://localhost:3000/root',
+ avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ dateTitle: '2017-03-23T23:02:00.807Z',
+ dateReadable: '12 hours ago',
});
});
- describe('components', () => {
- it('should have components', () => {
- expect(authorTimeComponent.components['mr-widget-author']).toBeDefined();
- });
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders provided action text', () => {
+ expect(vm.$el.textContent).toContain('Merged by');
});
- describe('template', () => {
- it('should have correct elements', () => {
- const el = createComponent().$el;
+ it('renders author', () => {
+ expect(vm.$el.textContent).toContain('Administrator');
+ });
- expect(el.tagName).toEqual('H4');
- expect(el.querySelector('a').getAttribute('href')).toEqual(props.author.webUrl);
- expect(el.querySelector('time').innerText).toContain(props.dateReadable);
- expect(el.querySelector('time').getAttribute('title')).toEqual(props.dateTitle);
- });
+ it('renders provided time', () => {
+ expect(vm.$el.querySelector('time').getAttribute('title')).toEqual('2017-03-23T23:02:00.807Z');
+ expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
index 06f89fabf42..13e5595bbfc 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
@@ -1,104 +1,219 @@
import Vue from 'vue';
-import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header';
-
-const createComponent = (mr) => {
- const Component = Vue.extend(headerComponent);
- return new Component({
- el: document.createElement('div'),
- propsData: { mr },
- });
-};
+import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetHeader', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr } = headerComponent.props;
+ let vm;
+ let Component;
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
- });
+ beforeEach(() => {
+ Component = Vue.extend(headerComponent);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
- let vm;
- beforeEach(() => {
- vm = createComponent({
- divergedCommitsCount: 12,
- sourceBranch: 'mr-widget-refactor',
- sourceBranchLink: '/foo/bar/mr-widget-refactor',
- targetBranch: 'master',
+ describe('shouldShowCommitsBehindText', () => {
+ it('return true when there are divergedCommitsCount', () => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 12,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
+ targetBranch: 'master',
+ } });
+
+ expect(vm.shouldShowCommitsBehindText).toEqual(true);
+ });
+
+ it('returns false where there are no divergedComits count', () => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 0,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
+ targetBranch: 'master',
+ } });
+ expect(vm.shouldShowCommitsBehindText).toEqual(false);
});
});
- it('shouldShowCommitsBehindText', () => {
- expect(vm.shouldShowCommitsBehindText).toBeTruthy();
+ describe('commitsText', () => {
+ it('returns singular when there is one commit', () => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 1,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
+ targetBranch: 'master',
+ } });
- vm.mr.divergedCommitsCount = 0;
- expect(vm.shouldShowCommitsBehindText).toBeFalsy();
- });
+ expect(vm.commitsText).toEqual('1 commit behind');
+ });
- it('commitsText', () => {
- expect(vm.commitsText).toEqual('commits');
+ it('returns plural when there is more than one commit', () => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 2,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">Link</a>',
+ targetBranch: 'master',
+ } });
- vm.mr.divergedCommitsCount = 1;
- expect(vm.commitsText).toEqual('commit');
+ expect(vm.commitsText).toEqual('2 commits behind');
+ });
});
});
describe('template', () => {
- let vm;
- let el;
- const sourceBranchPath = '/foo/bar/mr-widget-refactor';
- const mr = {
- divergedCommitsCount: 12,
- sourceBranch: 'mr-widget-refactor',
- sourceBranchLink: `<a href="${sourceBranchPath}">mr-widget-refactor</a>`,
- targetBranchPath: 'foo/bar/commits-path',
- targetBranchTreePath: 'foo/bar/tree/path',
- targetBranch: 'master',
- isOpen: true,
- emailPatchesPath: '/mr/email-patches',
- plainDiffPath: '/mr/plainDiffPath',
- };
-
- beforeEach(() => {
- vm = createComponent(mr);
- el = vm.$el;
+ describe('common elements', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 12,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
+ sourceBranchRemoved: false,
+ targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
+ targetBranch: 'master',
+ isOpen: true,
+ emailPatchesPath: '/mr/email-patches',
+ plainDiffPath: '/mr/plainDiffPath',
+ } });
+ });
+
+ it('renders source branch link', () => {
+ expect(
+ vm.$el.querySelector('.js-source-branch').innerHTML,
+ ).toEqual('<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>');
+ });
+
+ it('renders clipboard button', () => {
+ expect(vm.$el.querySelector('.btn-clipboard')).not.toEqual(null);
+ });
+
+ it('renders target branch', () => {
+ expect(vm.$el.querySelector('.js-target-branch').textContent.trim()).toEqual('master');
+ });
+ });
+
+ describe('with an open merge request', () => {
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ beforeEach(() => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 12,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
+ sourceBranchRemoved: false,
+ targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
+ targetBranch: 'master',
+ isOpen: true,
+ emailPatchesPath: '/mr/email-patches',
+ plainDiffPath: '/mr/plainDiffPath',
+ } });
+ });
+
+ it('renders checkout branch button with modal trigger', () => {
+ const button = vm.$el.querySelector('.js-check-out-branch');
+
+ expect(button.textContent.trim()).toEqual('Check out branch');
+ expect(button.getAttribute('data-target')).toEqual('#modal_merge_info');
+ expect(button.getAttribute('data-toggle')).toEqual('modal');
+ });
+
+ it('renders download dropdown with links', () => {
+ expect(
+ vm.$el.querySelector('.js-download-email-patches').textContent.trim(),
+ ).toEqual('Email patches');
+
+ expect(
+ vm.$el.querySelector('.js-download-email-patches').getAttribute('href'),
+ ).toEqual('/mr/email-patches');
+
+ expect(
+ vm.$el.querySelector('.js-download-plain-diff').textContent.trim(),
+ ).toEqual('Plain diff');
+
+ expect(
+ vm.$el.querySelector('.js-download-plain-diff').getAttribute('href'),
+ ).toEqual('/mr/plainDiffPath');
+ });
});
- it('should render template elements correctly', () => {
- expect(el.classList.contains('mr-source-target')).toBeTruthy();
- const sourceBranchLink = el.querySelectorAll('.label-branch')[0];
- const targetBranchLink = el.querySelectorAll('.label-branch')[1];
- const commitsCount = el.querySelector('.diverged-commits-count');
-
- expect(sourceBranchLink.textContent).toContain(mr.sourceBranch);
- expect(targetBranchLink.textContent).toContain(mr.targetBranch);
- expect(sourceBranchLink.querySelector('a').getAttribute('href')).toEqual(sourceBranchPath);
- expect(targetBranchLink.querySelector('a').getAttribute('href')).toEqual(mr.targetBranchTreePath);
- expect(commitsCount.textContent).toContain('12 commits behind');
- expect(commitsCount.querySelector('a').getAttribute('href')).toEqual(mr.targetBranchPath);
-
- expect(el.textContent).toContain('Check out branch');
- expect(el.querySelectorAll('.dropdown li a')[0].getAttribute('href')).toEqual(mr.emailPatchesPath);
- expect(el.querySelectorAll('.dropdown li a')[1].getAttribute('href')).toEqual(mr.plainDiffPath);
+ describe('with a closed merge request', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 12,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
+ sourceBranchRemoved: false,
+ targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
+ targetBranch: 'master',
+ isOpen: false,
+ emailPatchesPath: '/mr/email-patches',
+ plainDiffPath: '/mr/plainDiffPath',
+ } });
+ });
+
+ it('does not render checkout branch button with modal trigger', () => {
+ const button = vm.$el.querySelector('.js-check-out-branch');
+
+ expect(button).toEqual(null);
+ });
+
+ it('does not render download dropdown with links', () => {
+ expect(
+ vm.$el.querySelector('.js-download-email-patches'),
+ ).toEqual(null);
+
+ expect(
+ vm.$el.querySelector('.js-download-plain-diff'),
+ ).toEqual(null);
+ });
});
- it('should not have right action links if the MR state is not open', (done) => {
- vm.mr.isOpen = false;
- Vue.nextTick(() => {
- expect(el.textContent).not.toContain('Check out branch');
- expect(el.querySelectorAll('.dropdown li a').length).toEqual(0);
- done();
+ describe('without diverged commits', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 0,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
+ sourceBranchRemoved: false,
+ targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
+ targetBranch: 'master',
+ isOpen: true,
+ emailPatchesPath: '/mr/email-patches',
+ plainDiffPath: '/mr/plainDiffPath',
+ } });
+ });
+
+ it('does not render diverged commits info', () => {
+ expect(vm.$el.querySelector('.diverged-commits-count')).toEqual(null);
});
});
- it('should not render diverged commits count if the MR has no diverged commits', (done) => {
- vm.mr.divergedCommitsCount = null;
- Vue.nextTick(() => {
- expect(el.textContent).not.toContain('commits behind');
- expect(el.querySelectorAll('.diverged-commits-count').length).toEqual(0);
- done();
+ describe('with diverged commits', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, { mr: {
+ divergedCommitsCount: 12,
+ sourceBranch: 'mr-widget-refactor',
+ sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
+ sourceBranchRemoved: false,
+ targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
+ targetBranch: 'master',
+ isOpen: true,
+ emailPatchesPath: '/mr/email-patches',
+ plainDiffPath: '/mr/plainDiffPath',
+ } });
+ });
+
+ it('renders diverged commits info', () => {
+ expect(vm.$el.querySelector('.diverged-commits-count').textContent.trim()).toEqual('(12 commits behind)');
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js
index 4da4fc82c26..cc43639f576 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js
@@ -1,51 +1,56 @@
import Vue from 'vue';
-import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help';
-
-const props = {
- missingBranch: 'this-is-not-the-branch-you-are-looking-for',
-};
-const text = `If the ${props.missingBranch} branch exists in your local repository`;
-
-const createComponent = () => {
- const Component = Vue.extend(mergeHelpComponent);
- return new Component({
- el: document.createElement('div'),
- propsData: props,
- });
-};
+import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetMergeHelp', () => {
- describe('props', () => {
- it('should have props', () => {
- const { missingBranch } = mergeHelpComponent.props;
- const MissingBranchTypeClass = missingBranch.type;
-
- expect(new MissingBranchTypeClass() instanceof String).toBeTruthy();
- expect(missingBranch.required).toBeFalsy();
- expect(missingBranch.default).toEqual('');
- });
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(mergeHelpComponent);
});
- describe('template', () => {
- let vm;
- let el;
+ afterEach(() => {
+ vm.$destroy();
+ });
+ describe('with missing branch', () => {
beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
+ vm = mountComponent(Component, {
+ missingBranch: 'this-is-not-the-branch-you-are-looking-for',
+ });
});
- it('should have the correct elements', () => {
- expect(el.classList.contains('mr-widget-help')).toBeTruthy();
- expect(el.textContent).toContain(text);
+ it('renders missing branch information', () => {
+ expect(
+ vm.$el.textContent.trim().replace(/[\r\n]+/g, ' ').replace(/\s\s+/g, ' '),
+ ).toEqual(
+ 'If the this-is-not-the-branch-you-are-looking-for branch exists in your local repository, you can merge this merge request manually using the command line',
+ );
});
- it('should not show missing branch name if missingBranch props is not provided', (done) => {
- vm.missingBranch = null;
- Vue.nextTick(() => {
- expect(el.textContent).not.toContain(text);
- done();
- });
+ it('renders button to open help modal', () => {
+ expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-target')).toEqual('#modal_merge_info');
+ expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-toggle')).toEqual('modal');
+ });
+ });
+
+ describe('without missing branch', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component);
+ });
+
+ it('renders information about how to merge manually', () => {
+ expect(
+ vm.$el.textContent.trim().replace(/[\r\n]+/g, ' ').replace(/\s\s+/g, ' '),
+ ).toEqual(
+ 'You can merge this merge request manually using the command line',
+ );
+ });
+
+ it('renders element to open a modal', () => {
+ expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-target')).toEqual('#modal_merge_info');
+ expect(vm.$el.querySelector('.js-open-modal-help').getAttribute('data-toggle')).toEqual('modal');
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js
index f86fb6a0b4b..637bf483deb 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js
@@ -1,117 +1,82 @@
import Vue from 'vue';
-import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links';
+import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
-const createComponent = (data) => {
- const Component = Vue.extend(relatedLinksComponent);
+describe('MRWidgetRelatedLinks', () => {
+ let vm;
- return new Component({
- el: document.createElement('div'),
- propsData: data,
- });
-};
+ const createComponent = (data) => {
+ const Component = Vue.extend(relatedLinksComponent);
-describe('MRWidgetRelatedLinks', () => {
- describe('props', () => {
- it('should have props', () => {
- const { relatedLinks } = relatedLinksComponent.props;
+ return mountComponent(Component, data);
+ };
- expect(relatedLinks).toBeDefined();
- expect(relatedLinks.type instanceof Object).toBeTruthy();
- expect(relatedLinks.required).toBeTruthy();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
- const data = {
- relatedLinks: {
- closing: '/foo',
- mentioned: '/foo',
- assignToMe: '/foo',
- },
- };
-
- describe('hasLinks', () => {
- it('should return correct value when we have links reference', () => {
- const vm = createComponent(data);
- expect(vm.hasLinks).toBeTruthy();
-
- vm.relatedLinks.closing = null;
- expect(vm.hasLinks).toBeTruthy();
-
- vm.relatedLinks.mentioned = null;
- expect(vm.hasLinks).toBeTruthy();
-
- vm.relatedLinks.assignToMe = null;
- expect(vm.hasLinks).toBeFalsy();
- });
- });
-
describe('closesText', () => {
- it('returns correct text for open merge request', () => {
- data.state = 'open';
- const vm = createComponent(data);
+ it('returns Closes text for open merge request', () => {
+ vm = createComponent({ state: 'open', relatedLinks: {} });
expect(vm.closesText).toEqual('Closes');
});
it('returns correct text for closed merge request', () => {
- data.state = 'closed';
- const vm = createComponent(data);
+ vm = createComponent({ state: 'closed', relatedLinks: {} });
expect(vm.closesText).toEqual('Did not close');
});
it('returns correct tense for merged request', () => {
- data.state = 'merged';
- const vm = createComponent(data);
+ vm = createComponent({ state: 'merged', relatedLinks: {} });
expect(vm.closesText).toEqual('Closed');
});
});
});
- describe('template', () => {
- it('should have only have closing issues text', () => {
- const vm = createComponent({
- relatedLinks: {
- closing: '<a href="#">#23</a> and <a>#42</a>',
- },
- });
- const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim();
-
- expect(content).toContain('Closes #23 and #42');
- expect(content).not.toContain('Mentions');
+ it('should have only have closing issues text', () => {
+ vm = createComponent({
+ relatedLinks: {
+ closing: '<a href="#">#23</a> and <a>#42</a>',
+ },
});
+ const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim();
- it('should have only have mentioned issues text', () => {
- const vm = createComponent({
- relatedLinks: {
- mentioned: '<a href="#">#7</a>',
- },
- });
+ expect(content).toContain('Closes #23 and #42');
+ expect(content).not.toContain('Mentions');
+ });
- expect(vm.$el.innerText).toContain('Mentions #7');
- expect(vm.$el.innerText).not.toContain('Closes');
+ it('should have only have mentioned issues text', () => {
+ vm = createComponent({
+ relatedLinks: {
+ mentioned: '<a href="#">#7</a>',
+ },
});
- it('should have closing and mentioned issues at the same time', () => {
- const vm = createComponent({
- relatedLinks: {
- closing: '<a href="#">#7</a>',
- mentioned: '<a href="#">#23</a> and <a>#42</a>',
- },
- });
- const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim();
+ expect(vm.$el.innerText).toContain('Mentions #7');
+ expect(vm.$el.innerText).not.toContain('Closes');
+ });
- expect(content).toContain('Closes #7');
- expect(content).toContain('Mentions #23 and #42');
+ it('should have closing and mentioned issues at the same time', () => {
+ vm = createComponent({
+ relatedLinks: {
+ closing: '<a href="#">#7</a>',
+ mentioned: '<a href="#">#23</a> and <a>#42</a>',
+ },
});
+ const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim();
- it('should have assing issues link', () => {
- const vm = createComponent({
- relatedLinks: {
- assignToMe: '<a href="#">Assign yourself to these issues</a>',
- },
- });
+ expect(content).toContain('Closes #7');
+ expect(content).toContain('Mentions #23 and #42');
+ });
- expect(vm.$el.innerText).toContain('Assign yourself to these issues');
+ it('should have assing issues link', () => {
+ vm = createComponent({
+ relatedLinks: {
+ assignToMe: '<a href="#">Assign yourself to these issues</a>',
+ },
});
+
+ expect(vm.$el.innerText).toContain('Assign yourself to these issues');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js
new file mode 100644
index 00000000000..c39fcda0071
--- /dev/null
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js
@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import mrStatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('MR widget status icon component', () => {
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(mrStatusIcon);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('while loading', () => {
+ it('renders loading icon', () => {
+ vm = mountComponent(Component, { status: 'loading' });
+ expect(vm.$el.querySelector('.mr-widget-icon i').classList).toContain('fa-spinner');
+ });
+ });
+
+ describe('with status icon', () => {
+ it('renders ci status icon', () => {
+ vm = mountComponent(Component, { status: 'failed' });
+ expect(vm.$el.querySelector('.js-ci-status-icon-failed')).not.toBeNull();
+ });
+ });
+
+ describe('with disabled button', () => {
+ it('renders a disabled button', () => {
+ vm = mountComponent(Component, { status: 'failed', showDisabledButton: true });
+ expect(vm.$el.querySelector('.js-disabled-merge-button').textContent.trim()).toEqual('Merge');
+ });
+ });
+
+ describe('without disabled button', () => {
+ it('does not render a disabled button', () => {
+ vm = mountComponent(Component, { status: 'failed' });
+ expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js
index 6b7aa935ad3..658cadddb81 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js
@@ -1,19 +1,29 @@
import Vue from 'vue';
-import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking';
+import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetChecking', () => {
- describe('template', () => {
- it('should have correct elements', () => {
- const Component = Vue.extend(checkingComponent);
- const el = new Component({
- el: document.createElement('div'),
- }).$el;
+ let Component;
+ let vm;
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.querySelector('button').classList.contains('btn-success')).toBeTruthy();
- expect(el.querySelector('button').disabled).toBeTruthy();
- expect(el.innerText).toContain('Checking ability to merge automatically');
- expect(el.querySelector('i')).toBeDefined();
- });
+ beforeEach(() => {
+ Component = Vue.extend(checkingComponent);
+ vm = mountComponent(Component);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders disabled button', () => {
+ expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled');
+ });
+
+ it('renders loading icon', () => {
+ expect(vm.$el.querySelector('.mr-widget-icon i').classList).toContain('fa-spinner');
+ });
+
+ it('renders information about merging', () => {
+ expect(vm.$el.querySelector('.media-body').textContent.trim()).toEqual('Checking ability to merge automatically');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
index 1bf97bbf093..51a34739ee9 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
@@ -1,74 +1,58 @@
import Vue from 'vue';
-import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed';
-
-const mr = {
- targetBranch: 'good-branch',
- targetBranchPath: '/good-branch',
- metrics: {
- mergedBy: {},
- mergedAt: 'mergedUpdatedAt',
- closedBy: {
- name: 'Fatih Acet',
- username: 'fatihacet',
- },
- closedAt: 'closedEventUpdatedAt',
- readableMergedAt: '',
- readableClosedAt: '',
- },
- updatedAt: 'mrUpdatedAt',
- closedAt: '1 day ago',
-};
-
-const createComponent = () => {
- const Component = Vue.extend(closedComponent);
-
- return new Component({
- el: document.createElement('div'),
- propsData: { mr },
- });
-};
+import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetClosed', () => {
- describe('props', () => {
- it('should have props', () => {
- const mrProp = closedComponent.props.mr;
-
- expect(mrProp.type instanceof Object).toBeTruthy();
- expect(mrProp.required).toBeTruthy();
- });
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(closedComponent);
+ vm = mountComponent(Component, { mr: {
+ metrics: {
+ mergedBy: {},
+ closedBy: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://localhost:3000/root',
+ avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ mergedAt: 'Jan 24, 2018 1:02pm GMT+0000',
+ closedAt: 'Jan 24, 2018 1:02pm GMT+0000',
+ readableMergedAt: '',
+ readableClosedAt: 'less than a minute ago',
+ },
+ targetBranchPath: '/twitter/flight/commits/so_long_jquery',
+ targetBranch: 'so_long_jquery',
+ } });
});
- describe('components', () => {
- it('should have components added', () => {
- expect(closedComponent.components['mr-widget-author-and-time']).toBeDefined();
- });
+ afterEach(() => {
+ vm.$destroy();
});
- describe('template', () => {
- let vm;
- let el;
+ it('renders warning icon', () => {
+ expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull();
+ });
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
- });
+ it('renders closed by information with author and time', () => {
+ expect(
+ vm.$el.querySelector('.js-mr-widget-author').textContent.trim().replace(/\s\s+/g, ' '),
+ ).toContain(
+ 'Closed by Administrator less than a minute ago',
+ );
+ });
- afterEach(() => {
- vm.$destroy();
- });
+ it('links to the user that closed the MR', () => {
+ expect(vm.$el.querySelector('.author-link').getAttribute('href')).toEqual('http://localhost:3000/root');
+ });
- it('should have correct elements', () => {
- expect(el.querySelector('h4').textContent).toContain('Closed by');
- expect(el.querySelector('h4').textContent).toContain(mr.metrics.closedBy.name);
- expect(el.textContent).toContain('The changes were not merged into');
- expect(el.querySelector('.label-branch').getAttribute('href')).toEqual(mr.targetBranchPath);
- expect(el.querySelector('.label-branch').textContent).toContain(mr.targetBranch);
- });
+ it('renders information about the changes not being merged', () => {
+ expect(
+ vm.$el.querySelector('.mr-info-list').textContent.trim().replace(/\s\s+/g, ' '),
+ ).toContain('The changes were not merged into so_long_jquery');
+ });
- it('should use closedEvent updatedAt as tooltip title', () => {
- expect(
- el.querySelector('time').getAttribute('title'),
- ).toBe('closedEventUpdatedAt');
- });
+ it('renders link for target branch', () => {
+ expect(vm.$el.querySelector('.label-branch').getAttribute('href')).toEqual('/twitter/flight/commits/so_long_jquery');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
index 5d4c7ec09dc..a7d69fdcdb9 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
@@ -1,105 +1,85 @@
import Vue from 'vue';
-import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts';
+import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper';
-const ConflictsComponent = Vue.extend(conflictsComponent);
-const path = '/conflicts';
-
describe('MRWidgetConflicts', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr } = conflictsComponent.props;
+ let Component;
+ let vm;
+ const path = '/conflicts';
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
- });
+ beforeEach(() => {
+ Component = Vue.extend(conflictsComponent);
});
- describe('template', () => {
- describe('when allowed to merge', () => {
- let vm;
-
- beforeEach(() => {
- vm = mountComponent(ConflictsComponent, {
- mr: {
- canMerge: true,
- conflictResolutionPath: path,
- },
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('should tell you about conflicts without bothering other people', () => {
- expect(vm.$el.textContent).toContain('There are merge conflicts');
- expect(vm.$el.textContent).not.toContain('ask someone with write access');
- });
-
- it('should allow you to resolve the conflicts', () => {
- const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button');
+ afterEach(() => {
+ vm.$destroy();
+ });
- expect(resolveButton.textContent).toContain('Resolve conflicts');
- expect(resolveButton.getAttribute('href')).toEqual(path);
+ describe('when allowed to merge', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ mr: {
+ canMerge: true,
+ conflictResolutionPath: path,
+ },
});
+ });
- it('should have merge buttons', () => {
- const mergeButton = vm.$el.querySelector('.js-disabled-merge-button');
- const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button');
-
- expect(mergeButton.textContent).toContain('Merge');
- expect(mergeButton.disabled).toBeTruthy();
- expect(mergeButton.classList.contains('btn-success')).toEqual(true);
- expect(mergeLocallyButton.textContent).toContain('Merge locally');
- });
+ it('should tell you about conflicts without bothering other people', () => {
+ expect(vm.$el.textContent).toContain('There are merge conflicts');
+ expect(vm.$el.textContent).not.toContain('ask someone with write access');
});
- describe('when user does not have permission to merge', () => {
- let vm;
+ it('should allow you to resolve the conflicts', () => {
+ const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button');
- beforeEach(() => {
- vm = mountComponent(ConflictsComponent, {
- mr: {
- canMerge: false,
- },
- });
- });
+ expect(resolveButton.textContent).toContain('Resolve conflicts');
+ expect(resolveButton.getAttribute('href')).toEqual(path);
+ });
- afterEach(() => {
- vm.$destroy();
- });
+ it('should have merge buttons', () => {
+ const mergeButton = vm.$el.querySelector('.js-disabled-merge-button');
+ const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button');
- it('should show proper message', () => {
- expect(vm.$el.textContent).toContain('ask someone with write access');
- });
+ expect(mergeButton.textContent).toContain('Merge');
+ expect(mergeButton.disabled).toBeTruthy();
+ expect(mergeButton.classList.contains('btn-success')).toEqual(true);
+ expect(mergeLocallyButton.textContent).toContain('Merge locally');
+ });
+ });
- it('should not have action buttons', () => {
- expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined();
- expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull();
- expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull();
+ describe('when user does not have permission to merge', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ mr: {
+ canMerge: false,
+ },
});
});
- describe('when fast-forward or semi-linear merge enabled', () => {
- let vm;
+ it('should show proper message', () => {
+ expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('ask someone with write access');
+ });
- beforeEach(() => {
- vm = mountComponent(ConflictsComponent, {
- mr: {
- shouldBeRebased: true,
- },
- });
- });
+ it('should not have action buttons', () => {
+ expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined();
+ expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull();
+ expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull();
+ });
+ });
- afterEach(() => {
- vm.$destroy();
+ describe('when fast-forward or semi-linear merge enabled', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ mr: {
+ shouldBeRebased: true,
+ },
});
+ });
- it('should tell you to rebase locally', () => {
- expect(vm.$el.textContent).toContain('Fast-forward merge is not possible.');
- expect(vm.$el.textContent).toContain('To merge this request, first rebase locally');
- });
+ it('should tell you to rebase locally', () => {
+ expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('Fast-forward merge is not possible.');
+ expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('To merge this request, first rebase locally');
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
index cef365eec8a..a57b9811e08 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
@@ -1,45 +1,37 @@
import Vue from 'vue';
-import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge';
+import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
-
-const mr = {
- mergeError: 'Merge error happened.',
-};
-const createComponent = () => {
- const Component = Vue.extend(failedToMergeComponent);
- return new Component({
- el: document.createElement('div'),
- propsData: { mr },
- });
-};
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetFailedToMerge', () => {
- describe('data', () => {
- it('should have default data', () => {
- const data = failedToMergeComponent.data();
+ let Component;
+ let vm;
+
+ beforeEach(() => {
+ Component = Vue.extend(failedToMergeComponent);
+ spyOn(eventHub, '$emit');
+ vm = mountComponent(Component, { mr: {
+ mergeError: 'Merge error happened.',
+ } });
+ });
- expect(data.timer).toEqual(10);
- expect(data.isRefreshing).toBeFalsy();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
describe('timerText', () => {
it('should return correct timer text', () => {
- const vm = createComponent();
- expect(vm.timerText).toEqual('10 seconds');
+ expect(vm.timerText).toEqual('Refreshing in 10 seconds to show the updated status...');
vm.timer = 1;
- expect(vm.timerText).toEqual('a second');
+ expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...');
});
});
});
describe('created', () => {
it('should disable polling', () => {
- spyOn(eventHub, '$emit');
- createComponent();
-
expect(eventHub.$emit).toHaveBeenCalledWith('DisablePolling');
});
});
@@ -47,13 +39,10 @@ describe('MRWidgetFailedToMerge', () => {
describe('methods', () => {
describe('refresh', () => {
it('should emit event to request component refresh', () => {
- spyOn(eventHub, '$emit');
- const vm = createComponent();
-
- expect(vm.isRefreshing).toBeFalsy();
+ expect(vm.isRefreshing).toEqual(false);
vm.refresh();
- expect(vm.isRefreshing).toBeTruthy();
+ expect(vm.isRefreshing).toEqual(true);
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
expect(eventHub.$emit).toHaveBeenCalledWith('EnablePolling');
});
@@ -61,12 +50,11 @@ describe('MRWidgetFailedToMerge', () => {
describe('updateTimer', () => {
it('should update timer and emit event when timer end', () => {
- const vm = createComponent();
spyOn(vm, 'refresh');
expect(vm.timer).toEqual(10);
- for (let i = 0; i < 10; i++) { // eslint-disable-line
+ for (let i = 0; i < 10; i += 1) {
expect(vm.timer).toEqual(10 - i);
vm.updateTimer();
}
@@ -76,47 +64,54 @@ describe('MRWidgetFailedToMerge', () => {
});
});
- describe('template', () => {
- let vm;
- let el;
+ describe('while it is refreshing', () => {
+ it('renders Refresing now', (done) => {
+ vm.isRefreshing = true;
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.js-refresh-label').textContent.trim()).toEqual('Refreshing now');
+ done();
+ });
});
+ });
- it('should have correct elements', (done) => {
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.innerText).toContain('Merge error happened.');
- expect(el.innerText).toContain('Refreshing in 10 seconds');
- expect(el.innerText).not.toContain('Merge failed.');
- expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy();
- expect(el.querySelector('button').innerText).toContain('Merge');
- expect(el.querySelector('.js-refresh-button').innerText).toContain('Refresh now');
- expect(el.querySelector('.js-refresh-label')).toEqual(null);
- expect(el.innerText).not.toContain('Refreshing now');
- setTimeout(() => {
- expect(el.innerText).toContain('Refreshing in 9 seconds');
- done();
- }, 1010);
+ describe('while it is not regresing', () => {
+ it('renders warning icon and disabled merge button', () => {
+ expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull();
+ expect(vm.$el.querySelector('.js-disabled-merge-button').getAttribute('disabled')).toEqual('disabled');
+ });
+
+ it('renders given error', () => {
+ expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual('Merge error happened..');
});
- it('should just generic merge failed message if merge_error is not available', (done) => {
- vm.mr.mergeError = null;
+ it('renders refresh button', () => {
+ expect(vm.$el.querySelector('.js-refresh-button').textContent.trim()).toEqual('Refresh now');
+ });
- Vue.nextTick(() => {
- expect(el.innerText).toContain('Merge failed.');
- expect(el.innerText).not.toContain('Merge error happened.');
- done();
- });
+ it('renders remaining time', () => {
+ expect(
+ vm.$el.querySelector('.has-custom-error').textContent.trim(),
+ ).toEqual('Refreshing in 10 seconds to show the updated status...');
+ });
+ });
+
+ it('should just generic merge failed message if merge_error is not available', (done) => {
+ vm.mr.mergeError = null;
+
+ Vue.nextTick(() => {
+ expect(vm.$el.innerText).toContain('Merge failed.');
+ expect(vm.$el.innerText).not.toContain('Merge error happened.');
+ done();
});
+ });
- it('should show refresh label when refresh requested', () => {
- vm.refresh();
- Vue.nextTick(() => {
- expect(el.innerText).not.toContain('Merge failed. Refreshing');
- expect(el.innerText).toContain('Refreshing now');
- });
+ it('should show refresh label when refresh requested', (done) => {
+ vm.refresh();
+ Vue.nextTick(() => {
+ expect(vm.$el.innerText).not.toContain('Merge failed. Refreshing');
+ expect(vm.$el.innerText).toContain('Refreshing now');
+ done();
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js
deleted file mode 100644
index 237035648cf..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import Vue from 'vue';
-import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging';
-
-describe('MRWidgetMerging', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr } = mergingComponent.props;
-
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
- });
- });
-
- describe('template', () => {
- it('should have correct elements', () => {
- const Component = Vue.extend(mergingComponent);
- const mr = {
- targetBranchPath: '/branch-path',
- targetBranch: 'branch',
- };
- const el = new Component({
- el: document.createElement('div'),
- propsData: { mr },
- }).$el;
-
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.innerText).toContain('This merge request is in the process of being merged');
- expect(el.innerText).toContain('changes will be merged into');
- expect(el.querySelector('.label-branch a').getAttribute('href')).toEqual(mr.targetBranchPath);
- expect(el.querySelector('.label-branch a').textContent).toContain(mr.targetBranch);
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js
index 5f4df15bcd6..df56c4e2c5c 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js
@@ -1,77 +1,50 @@
import Vue from 'vue';
-import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds';
+import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
-
-const targetBranchPath = '/foo/bar';
-const targetBranch = 'foo';
-const sha = '1EA2EZ34';
-
-const createComponent = () => {
- const Component = Vue.extend(mwpsComponent);
- const mr = {
- shouldRemoveSourceBranch: false,
- canRemoveSourceBranch: true,
- canCancelAutomaticMerge: true,
- mergeUserId: 1,
- currentUserId: 1,
- setToMWPSBy: {},
- sha,
- targetBranchPath,
- targetBranch,
- };
-
- const service = {
- cancelAutomaticMerge() {},
- mergeResource: {
- save() {},
- },
- };
-
- return new Component({
- el: document.createElement('div'),
- propsData: { mr, service },
- });
-};
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetMergeWhenPipelineSucceeds', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr, service } = mwpsComponent.props;
-
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
-
- expect(service.type instanceof Object).toBeTruthy();
- expect(service.required).toBeTruthy();
+ let vm;
+ const targetBranchPath = '/foo/bar';
+ const targetBranch = 'foo';
+ const sha = '1EA2EZ34';
+
+ beforeEach(() => {
+ const Component = Vue.extend(mwpsComponent);
+ spyOn(eventHub, '$emit');
+
+ vm = mountComponent(Component, {
+ mr: {
+ shouldRemoveSourceBranch: false,
+ canRemoveSourceBranch: true,
+ canCancelAutomaticMerge: true,
+ mergeUserId: 1,
+ currentUserId: 1,
+ setToMWPSBy: {},
+ sha,
+ targetBranchPath,
+ targetBranch,
+ },
+ service: {
+ cancelAutomaticMerge() {},
+ mergeResource: {
+ save() {},
+ },
+ },
});
});
- describe('components', () => {
- it('should have components added', () => {
- expect(mwpsComponent.components['mr-widget-author']).toBeDefined();
- });
- });
-
- describe('data', () => {
- it('should have default data', () => {
- const data = mwpsComponent.data();
-
- expect(data.isCancellingAutoMerge).toBeFalsy();
- expect(data.isRemovingSourceBranch).toBeFalsy();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
describe('canRemoveSourceBranch', () => {
it('should return true when user is able to remove source branch', () => {
- const vm = createComponent();
-
expect(vm.canRemoveSourceBranch).toBeTruthy();
});
it('should return false when user id is not the same with who set the MWPS', () => {
- const vm = createComponent();
-
vm.mr.mergeUserId = 2;
expect(vm.canRemoveSourceBranch).toBeFalsy();
@@ -83,15 +56,11 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
});
it('should return false when shouldRemoveSourceBranch set to false', () => {
- const vm = createComponent();
-
vm.mr.shouldRemoveSourceBranch = true;
expect(vm.canRemoveSourceBranch).toBeFalsy();
});
it('should return false if user is not able to remove the source branch', () => {
- const vm = createComponent();
-
vm.mr.canRemoveSourceBranch = false;
expect(vm.canRemoveSourceBranch).toBeFalsy();
});
@@ -101,11 +70,9 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
describe('methods', () => {
describe('cancelAutomaticMerge', () => {
it('should set flag and call service then tell main component to update the widget with data', (done) => {
- const vm = createComponent();
const mrObj = {
is_new_mr_data: true,
};
- spyOn(eventHub, '$emit');
spyOn(vm.service, 'cancelAutomaticMerge').and.returnValue(new Promise((resolve) => {
resolve({
data: mrObj,
@@ -123,8 +90,6 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
describe('removeSourceBranch', () => {
it('should set flag and call service then request main component to update the widget', (done) => {
- const vm = createComponent();
- spyOn(eventHub, '$emit');
spyOn(vm.service.mergeResource, 'save').and.returnValue(new Promise((resolve) => {
resolve({
data: {
@@ -148,31 +113,23 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
});
describe('template', () => {
- let vm;
- let el;
-
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
- });
-
it('should have correct elements', () => {
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.innerText).toContain('to be merged automatically when the pipeline succeeds');
- expect(el.innerText).toContain('The changes will be merged into');
- expect(el.innerText).toContain(targetBranch);
- expect(el.innerText).toContain('The source branch will not be removed');
- expect(el.querySelector('.js-cancel-auto-merge').innerText).toContain('Cancel automatic merge');
- expect(el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeFalsy();
- expect(el.querySelector('.js-remove-source-branch').innerText).toContain('Remove source branch');
- expect(el.querySelector('.js-remove-source-branch').getAttribute('disabled')).toBeFalsy();
+ expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
+ expect(vm.$el.innerText).toContain('to be merged automatically when the pipeline succeeds');
+ expect(vm.$el.innerText).toContain('The changes will be merged into');
+ expect(vm.$el.innerText).toContain(targetBranch);
+ expect(vm.$el.innerText).toContain('The source branch will not be removed');
+ expect(vm.$el.querySelector('.js-cancel-auto-merge').innerText).toContain('Cancel automatic merge');
+ expect(vm.$el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeFalsy();
+ expect(vm.$el.querySelector('.js-remove-source-branch').innerText).toContain('Remove source branch');
+ expect(vm.$el.querySelector('.js-remove-source-branch').getAttribute('disabled')).toBeFalsy();
});
it('should disable cancel auto merge button when the action is in progress', (done) => {
vm.isCancellingAutoMerge = true;
Vue.nextTick(() => {
- expect(el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeTruthy();
+ expect(vm.$el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeTruthy();
done();
});
});
@@ -181,7 +138,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
vm.mr.shouldRemoveSourceBranch = true;
Vue.nextTick(() => {
- const normalizedText = el.innerText.replace(/\s+/g, ' ');
+ const normalizedText = vm.$el.innerText.replace(/\s+/g, ' ');
expect(normalizedText).toContain('The source branch will be removed');
expect(normalizedText).not.toContain('The source branch will not be removed');
done();
@@ -192,7 +149,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
vm.mr.currentUserId = 4;
Vue.nextTick(() => {
- expect(el.querySelector('.js-remove-source-branch')).toEqual(null);
+ expect(vm.$el.querySelector('.js-remove-source-branch')).toEqual(null);
done();
});
});
@@ -201,7 +158,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
vm.isRemovingSourceBranch = true;
Vue.nextTick(() => {
- expect(el.querySelector('.js-remove-source-branch').getAttribute('disabled')).toBeTruthy();
+ expect(vm.$el.querySelector('.js-remove-source-branch').getAttribute('disabled')).toBeTruthy();
done();
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
index 2dc3b72ea40..43a989393ba 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -1,108 +1,99 @@
import Vue from 'vue';
-import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged';
+import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
-
-const targetBranch = 'foo';
-
-const createComponent = () => {
- const Component = Vue.extend(mergedComponent);
- const mr = {
- isRemovingSourceBranch: false,
- cherryPickInForkPath: false,
- canCherryPickInCurrentMR: true,
- revertInForkPath: false,
- canRevertInCurrentMR: true,
- canRemoveSourceBranch: true,
- sourceBranchRemoved: true,
- metrics: {
- mergedBy: {},
- mergedAt: 'mergedUpdatedAt',
- readableMergedAt: '',
- closedBy: {},
- closedAt: 'mergedUpdatedAt',
- readableClosedAt: '',
- },
- updatedAt: 'mrUpdatedAt',
- targetBranch,
- };
-
- const service = {
- removeSourceBranch() {},
- };
-
- return new Component({
- el: document.createElement('div'),
- propsData: { mr, service },
- });
-};
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetMerged', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr, service } = mergedComponent.props;
-
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
-
- expect(service.type instanceof Object).toBeTruthy();
- expect(service.required).toBeTruthy();
- });
- });
-
- describe('components', () => {
- it('should have components added', () => {
- expect(mergedComponent.components['mr-widget-author-and-time']).toBeDefined();
- });
+ let vm;
+ const targetBranch = 'foo';
+
+ beforeEach(() => {
+ const Component = Vue.extend(mergedComponent);
+ const mr = {
+ isRemovingSourceBranch: false,
+ cherryPickInForkPath: false,
+ canCherryPickInCurrentMR: true,
+ revertInForkPath: false,
+ canRevertInCurrentMR: true,
+ canRemoveSourceBranch: true,
+ sourceBranchRemoved: true,
+ metrics: {
+ mergedBy: {
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://localhost:3000/root',
+ avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ mergedAt: 'Jan 24, 2018 1:02pm GMT+0000',
+ readableMergedAt: '',
+ closedBy: {},
+ closedAt: 'Jan 24, 2018 1:02pm GMT+0000',
+ readableClosedAt: '',
+ },
+ updatedAt: 'mergedUpdatedAt',
+ targetBranch,
+ };
+
+ const service = {
+ removeSourceBranch() {},
+ };
+
+ spyOn(eventHub, '$emit');
+
+ vm = mountComponent(Component, { mr, service });
});
- describe('data', () => {
- it('should have default data', () => {
- const data = mergedComponent.data();
-
- expect(data.isMakingRequest).toBeFalsy();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
describe('shouldShowRemoveSourceBranch', () => {
- it('should correct value when fields changed', () => {
- const vm = createComponent();
+ it('returns true when sourceBranchRemoved is false', () => {
vm.mr.sourceBranchRemoved = false;
- expect(vm.shouldShowRemoveSourceBranch).toBeTruthy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(true);
+ });
+ it('returns false wehn sourceBranchRemoved is true', () => {
vm.mr.sourceBranchRemoved = true;
- expect(vm.shouldShowRemoveSourceBranch).toBeFalsy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
+ });
+ it('returns false when canRemoveSourceBranch is false', () => {
vm.mr.sourceBranchRemoved = false;
vm.mr.canRemoveSourceBranch = false;
- expect(vm.shouldShowRemoveSourceBranch).toBeFalsy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
+ });
+ it('returns false when is making request', () => {
vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true;
- expect(vm.shouldShowRemoveSourceBranch).toBeFalsy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
+ });
+ it('returns true when all are true', () => {
vm.mr.isRemovingSourceBranch = true;
vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true;
- expect(vm.shouldShowRemoveSourceBranch).toBeFalsy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
});
+
describe('shouldShowSourceBranchRemoving', () => {
it('should correct value when fields changed', () => {
- const vm = createComponent();
vm.mr.sourceBranchRemoved = false;
- expect(vm.shouldShowSourceBranchRemoving).toBeFalsy();
+ expect(vm.shouldShowSourceBranchRemoving).toEqual(false);
vm.mr.sourceBranchRemoved = true;
- expect(vm.shouldShowRemoveSourceBranch).toBeFalsy();
+ expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
vm.mr.sourceBranchRemoved = false;
vm.isMakingRequest = true;
- expect(vm.shouldShowSourceBranchRemoving).toBeTruthy();
+ expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
vm.isMakingRequest = false;
vm.mr.isRemovingSourceBranch = true;
- expect(vm.shouldShowSourceBranchRemoving).toBeTruthy();
+ expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
});
});
});
@@ -110,8 +101,6 @@ describe('MRWidgetMerged', () => {
describe('methods', () => {
describe('removeSourceBranch', () => {
it('should set flag and call service then request main component to update the widget', (done) => {
- const vm = createComponent();
- spyOn(eventHub, '$emit');
spyOn(vm.service, 'removeSourceBranch').and.returnValue(new Promise((resolve) => {
resolve({
data: {
@@ -123,7 +112,7 @@ describe('MRWidgetMerged', () => {
vm.removeSourceBranch();
setTimeout(() => {
const args = eventHub.$emit.calls.argsFor(0);
- expect(vm.isMakingRequest).toBeTruthy();
+ expect(vm.isMakingRequest).toEqual(true);
expect(args[0]).toEqual('MRWidgetUpdateRequested');
expect(args[1]).not.toThrow();
done();
@@ -132,53 +121,50 @@ describe('MRWidgetMerged', () => {
});
});
- describe('template', () => {
- let vm;
- let el;
+ it('has merged by information', () => {
+ expect(vm.$el.textContent).toContain('Merged by');
+ expect(vm.$el.textContent).toContain('Administrator');
+ });
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
- });
+ it('renders branch information', () => {
+ expect(vm.$el.textContent).toContain('The changes were merged into');
+ expect(vm.$el.textContent).toContain(targetBranch);
+ });
- it('should have correct elements', () => {
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.querySelector('.js-mr-widget-author')).toBeDefined();
- expect(el.innerText).toContain('The changes were merged into');
- expect(el.innerText).toContain(targetBranch);
- expect(el.innerText).toContain('The source branch has been removed');
- expect(el.innerText).toContain('Revert');
- expect(el.innerText).toContain('Cherry-pick');
- expect(el.innerText).not.toContain('You can remove source branch now');
- expect(el.innerText).not.toContain('The source branch is being removed');
- });
+ it('renders information about branch being removed', () => {
+ expect(vm.$el.textContent).toContain('The source branch has been removed');
+ });
- it('should not show source branch removed text', (done) => {
- vm.mr.sourceBranchRemoved = false;
+ it('shows revert and cherry-pick buttons', () => {
+ expect(vm.$el.textContent).toContain('Revert');
+ expect(vm.$el.textContent).toContain('Cherry-pick');
+ });
- Vue.nextTick(() => {
- expect(el.innerText).toContain('You can remove source branch now');
- expect(el.innerText).not.toContain('The source branch has been removed');
- done();
- });
+ it('should not show source branch removed text', (done) => {
+ vm.mr.sourceBranchRemoved = false;
+
+ Vue.nextTick(() => {
+ expect(vm.$el.innerText).toContain('You can remove source branch now');
+ expect(vm.$el.innerText).not.toContain('The source branch has been removed');
+ done();
});
+ });
- it('should show source branch removing text', (done) => {
- vm.mr.isRemovingSourceBranch = true;
- vm.mr.sourceBranchRemoved = false;
+ it('should show source branch removing text', (done) => {
+ vm.mr.isRemovingSourceBranch = true;
+ vm.mr.sourceBranchRemoved = false;
- Vue.nextTick(() => {
- expect(el.innerText).toContain('The source branch is being removed');
- expect(el.innerText).not.toContain('You can remove source branch now');
- expect(el.innerText).not.toContain('The source branch has been removed');
- done();
- });
+ Vue.nextTick(() => {
+ expect(vm.$el.innerText).toContain('The source branch is being removed');
+ expect(vm.$el.innerText).not.toContain('You can remove source branch now');
+ expect(vm.$el.innerText).not.toContain('The source branch has been removed');
+ done();
});
+ });
- it('should use mergedEvent updatedAt as tooltip title', () => {
- expect(
- el.querySelector('time').getAttribute('title'),
- ).toBe('mergedUpdatedAt');
- });
+ it('should use mergedEvent mergedAt as tooltip title', () => {
+ expect(
+ vm.$el.querySelector('time').getAttribute('title'),
+ ).toBe('Jan 24, 2018 1:02pm GMT+0000');
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js
new file mode 100644
index 00000000000..0b2ed2d4086
--- /dev/null
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js
@@ -0,0 +1,34 @@
+import Vue from 'vue';
+import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('MRWidgetMerging', () => {
+ let vm;
+ beforeEach(() => {
+ const Component = Vue.extend(mergingComponent);
+
+ vm = mountComponent(Component, { mr: {
+ targetBranchPath: '/branch-path',
+ targetBranch: 'branch',
+ } });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders information about merge request being merged', () => {
+ expect(
+ vm.$el.querySelector('.media-body').textContent.trim().replace(/\s\s+/g, ' ').replace(/[\r\n]+/g, ' '),
+ ).toContain('This merge request is in the process of being merged');
+ });
+
+ it('renders branch information', () => {
+ expect(
+ vm.$el.querySelector('.mr-info-list').textContent.trim().replace(/\s\s+/g, ' ').replace(/[\r\n]+/g, ' '),
+ ).toEqual('The changes will be merged into branch');
+ expect(
+ vm.$el.querySelector('a').getAttribute('href'),
+ ).toEqual('/branch-path');
+ });
+});
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index ae494267659..3dd75307484 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -38,7 +38,7 @@ export default {
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
},
"merged_at": "2017-04-07T15:39:25.696Z",
@@ -50,7 +50,7 @@ export default {
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
},
"merge_user": null,
@@ -64,7 +64,7 @@ export default {
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
},
"active": false,
@@ -159,10 +159,10 @@ export default {
"username": "root",
"id": 1,
"state": "active",
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "avatar_url": "https://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",
+ "author_gravatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"commit_url": "http://localhost:3000/root/acets-app/commit/104096c51715e12e7ae41f9333e9fa35b73f385d",
"commit_path": "/root/acets-app/commit/104096c51715e12e7ae41f9333e9fa35b73f385d"
},
diff --git a/spec/javascripts/vue_shared/components/confirmation_input_spec.js b/spec/javascripts/vue_shared/components/confirmation_input_spec.js
new file mode 100644
index 00000000000..a6a12614e77
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/confirmation_input_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import confirmationInput from '~/vue_shared/components/confirmation_input.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Confirmation input component', () => {
+ const Component = Vue.extend(confirmationInput);
+ const props = {
+ inputId: 'dummy-id',
+ confirmationKey: 'confirmation-key',
+ confirmationValue: 'confirmation-value',
+ };
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('props', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ });
+
+ it('sets id of the input field to inputId', () => {
+ expect(vm.$refs.enteredValue.id).toBe(props.inputId);
+ });
+
+ it('sets name of the input field to confirmationKey', () => {
+ expect(vm.$refs.enteredValue.name).toBe(props.confirmationKey);
+ });
+ });
+
+ describe('computed', () => {
+ describe('inputLabel', () => {
+ it('escapes confirmationValue by default', () => {
+ vm = mountComponent(Component, { ...props, confirmationValue: 'n<e></e>ds escap"ng' });
+ expect(vm.inputLabel).toBe('Type <code>n&lt;e&gt;&lt;/e&gt;ds escap&quot;ng</code> to confirm:');
+ });
+
+ it('does not escape confirmationValue if escapeValue is false', () => {
+ vm = mountComponent(Component, { ...props, confirmationValue: 'n<e></e>ds escap"ng', shouldEscapeConfirmationValue: false });
+ expect(vm.inputLabel).toBe('Type <code>n<e></e>ds escap"ng</code> to confirm:');
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('hasCorrectValue', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ });
+
+ it('returns false if entered value is incorrect', () => {
+ vm.$refs.enteredValue.value = 'incorrect';
+ expect(vm.hasCorrectValue()).toBe(false);
+ });
+
+ it('returns true if entered value is correct', () => {
+ vm.$refs.enteredValue.value = props.confirmationValue;
+ expect(vm.hasCorrectValue()).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/modal_spec.js b/spec/javascripts/vue_shared/components/modal_spec.js
index fe75a86cac8..a5f9c75be4e 100644
--- a/spec/javascripts/vue_shared/components/modal_spec.js
+++ b/spec/javascripts/vue_shared/components/modal_spec.js
@@ -25,7 +25,7 @@ describe('Modal', () => {
});
describe('with id', () => {
- it('does not render a primary button', () => {
+ describe('does not render a primary button', () => {
beforeEach(() => {
vm = mountComponent(modalComponent, {
id: 'my-modal',
diff --git a/spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js b/spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
index 20363e78094..2de108da2ac 100644
--- a/spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
+++ b/spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
@@ -21,22 +21,21 @@ describe('collapsedGroupedDatePicker', () => {
});
});
- it('toggleCollapse events', () => {
- const toggleCollapse = jasmine.createSpy();
-
+ describe('toggleCollapse events', () => {
beforeEach((done) => {
+ spyOn(vm, 'toggleSidebar');
vm.minDate = new Date('07/17/2016');
Vue.nextTick(done);
});
it('should emit when sidebar is toggled', () => {
vm.$el.querySelector('.gutter-toggle').click();
- expect(toggleCollapse).toHaveBeenCalled();
+ expect(vm.toggleSidebar).toHaveBeenCalled();
});
it('should emit when collapsed-calendar-icon is clicked', () => {
vm.$el.querySelector('.sidebar-collapsed-icon').click();
- expect(toggleCollapse).toHaveBeenCalled();
+ expect(vm.toggleSidebar).toHaveBeenCalled();
});
});