Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/javascripts
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/awards_handler_spec.js400
-rw-r--r--spec/javascripts/behaviors/autosize_spec.js20
-rw-r--r--spec/javascripts/behaviors/copy_as_gfm_spec.js125
-rw-r--r--spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js52
-rw-r--r--spec/javascripts/behaviors/markdown/highlight_current_user_spec.js55
-rw-r--r--spec/javascripts/behaviors/requires_input_spec.js62
-rw-r--r--spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js315
-rw-r--r--spec/javascripts/boards/board_list_common_spec.js66
-rw-r--r--spec/javascripts/collapsed_sidebar_todo_spec.js171
-rw-r--r--spec/javascripts/comment_type_toggle_spec.js168
-rw-r--r--spec/javascripts/droplab/drop_down_spec.js650
-rw-r--r--spec/javascripts/droplab/hook_spec.js73
-rw-r--r--spec/javascripts/droplab/plugins/input_setter_spec.js214
-rw-r--r--spec/javascripts/dropzone_input_spec.js109
-rw-r--r--spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js126
-rw-r--r--spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js722
-rw-r--r--spec/javascripts/gl_dropdown_spec.js341
-rw-r--r--spec/javascripts/gl_form_spec.js110
-rw-r--r--spec/javascripts/helpers/scroll_into_view_promise.js28
-rw-r--r--spec/javascripts/helpers/vuex_action_helper_spec.js166
-rw-r--r--spec/javascripts/helpers/wait_for_attribute_change.js16
-rw-r--r--spec/javascripts/ide/components/commit_sidebar/message_field_spec.js170
-rw-r--r--spec/javascripts/ide/components/jobs/detail_spec.js184
-rw-r--r--spec/javascripts/ide/components/repo_editor_spec.js512
-rw-r--r--spec/javascripts/ide/helpers.js1
-rw-r--r--spec/javascripts/ide/mock_data.js1
-rw-r--r--spec/javascripts/ide/stores/actions/merge_request_spec.js510
-rw-r--r--spec/javascripts/ide/stores/actions/project_spec.js404
-rw-r--r--spec/javascripts/ide/stores/actions/tree_spec.js216
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js1116
-rw-r--r--spec/javascripts/ide/stores/modules/commit/actions_spec.js603
-rw-r--r--spec/javascripts/importer_status_spec.js138
-rw-r--r--spec/javascripts/labels_issue_sidebar_spec.js97
-rw-r--r--spec/javascripts/lazy_loader_spec.js244
-rw-r--r--spec/javascripts/line_highlighter_spec.js261
-rw-r--r--spec/javascripts/merge_request_spec.js187
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js283
-rw-r--r--spec/javascripts/mini_pipeline_graph_dropdown_spec.js106
-rw-r--r--spec/javascripts/pager_spec.js162
-rw-r--r--spec/javascripts/pdf/index_spec.js58
-rw-r--r--spec/javascripts/pdf/page_spec.js49
-rw-r--r--spec/javascripts/performance_bar/index_spec.js80
-rw-r--r--spec/javascripts/persistent_user_callout_spec.js175
-rw-r--r--spec/javascripts/read_more_spec.js23
-rw-r--r--spec/javascripts/releases/components/app_index_spec.js184
-rw-r--r--spec/javascripts/releases/mock_data.js148
-rw-r--r--spec/javascripts/releases/stores/modules/list/actions_spec.js131
-rw-r--r--spec/javascripts/releases/stores/modules/list/helpers.js6
-rw-r--r--spec/javascripts/releases/stores/modules/list/mutations_spec.js55
-rw-r--r--spec/javascripts/right_sidebar_spec.js87
-rw-r--r--spec/javascripts/search_autocomplete_spec.js215
-rw-r--r--spec/javascripts/shortcuts_spec.js46
-rw-r--r--spec/javascripts/signin_tabs_memoizer_spec.js216
-rw-r--r--spec/javascripts/todos_spec.js108
-rw-r--r--spec/javascripts/toggle_buttons_spec.js127
-rw-r--r--spec/javascripts/user_popovers_spec.js95
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js76
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js39
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js44
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js313
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js223
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js70
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js326
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js141
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js85
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js48
-rw-r--r--spec/javascripts/vue_mr_widget/components/review_app_link_spec.js52
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js31
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js230
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js31
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js69
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js225
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js156
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js219
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js43
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js40
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js26
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js34
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js26
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js19
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js983
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js25
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js99
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js45
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js99
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js2
-rw-r--r--spec/javascripts/vue_shared/components/deprecated_modal_2_spec.js261
-rw-r--r--spec/javascripts/vue_shared/components/deprecated_modal_spec.js71
-rw-r--r--spec/javascripts/vue_shared/components/file_finder/index_spec.js368
-rw-r--r--spec/javascripts/vue_shared/components/icon_spec.js73
-rw-r--r--spec/javascripts/vue_shared/components/issue/related_issuable_mock_data.js1
-rw-r--r--spec/javascripts/vue_shared/components/panel_resizer_spec.js85
-rw-r--r--spec/javascripts/vue_shared/components/smart_virtual_list_spec.js83
-rw-r--r--spec/javascripts/vue_shared/directives/autofocusonshow_spec.js38
-rw-r--r--spec/javascripts/vue_shared/directives/tooltip_spec.js89
-rw-r--r--spec/javascripts/vue_shared/translate_spec.js251
-rw-r--r--spec/javascripts/vuex_shared/modules/modal/actions_spec.js31
-rw-r--r--spec/javascripts/zen_mode_spec.js106
98 files changed, 0 insertions, 16263 deletions
diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js
deleted file mode 100644
index 02200f77ad7..00000000000
--- a/spec/javascripts/awards_handler_spec.js
+++ /dev/null
@@ -1,400 +0,0 @@
-import $ from 'jquery';
-import Cookies from 'js-cookie';
-import loadAwardsHandler from '~/awards_handler';
-import '~/lib/utils/common_utils';
-
-window.gl = window.gl || {};
-window.gon = window.gon || {};
-
-let openAndWaitForEmojiMenu;
-let awardsHandler = null;
-const urlRoot = gon.relative_url_root;
-
-const lazyAssert = function(done, assertFn) {
- setTimeout(function() {
- assertFn();
- done();
- // Maybe jasmine.clock here?
- }, 333);
-};
-
-describe('AwardsHandler', function() {
- preloadFixtures('snippets/show.html');
- beforeEach(function(done) {
- loadFixtures('snippets/show.html');
- loadAwardsHandler(true)
- .then(obj => {
- awardsHandler = obj;
- spyOn(awardsHandler, 'postEmoji').and.callFake((button, url, emoji, cb) => cb());
- done();
- })
- .catch(fail);
-
- let isEmojiMenuBuilt = false;
- openAndWaitForEmojiMenu = function() {
- return new Promise(resolve => {
- if (isEmojiMenuBuilt) {
- resolve();
- } else {
- $('.js-add-award')
- .eq(0)
- .click();
- const $menu = $('.emoji-menu');
- $menu.one('build-emoji-menu-finish', () => {
- isEmojiMenuBuilt = true;
- resolve();
- });
- }
- });
- };
- });
-
- afterEach(function() {
- // restore original url root value
- gon.relative_url_root = urlRoot;
-
- // Undo what we did to the shared <body>
- $('body').removeAttr('data-page');
-
- awardsHandler.destroy();
- });
-
- describe('::showEmojiMenu', function() {
- it('should show emoji menu when Add emoji button clicked', function(done) {
- $('.js-add-award')
- .eq(0)
- .click();
- lazyAssert(done, function() {
- const $emojiMenu = $('.emoji-menu');
-
- expect($emojiMenu.length).toBe(1);
- expect($emojiMenu.hasClass('is-visible')).toBe(true);
- expect($emojiMenu.find('.js-emoji-menu-search').length).toBe(1);
- expect($('.js-awards-block.current').length).toBe(1);
- });
- });
-
- it('should also show emoji menu for the smiley icon in notes', function(done) {
- $('.js-add-award.note-action-button').click();
- lazyAssert(done, function() {
- const $emojiMenu = $('.emoji-menu');
-
- expect($emojiMenu.length).toBe(1);
- });
- });
-
- it('should remove emoji menu when body is clicked', function(done) {
- $('.js-add-award')
- .eq(0)
- .click();
- lazyAssert(done, function() {
- const $emojiMenu = $('.emoji-menu');
- $('body').click();
-
- expect($emojiMenu.length).toBe(1);
- expect($emojiMenu.hasClass('is-visible')).toBe(false);
- expect($('.js-awards-block.current').length).toBe(0);
- });
- });
-
- it('should not remove emoji menu when search is clicked', function(done) {
- $('.js-add-award')
- .eq(0)
- .click();
- lazyAssert(done, function() {
- const $emojiMenu = $('.emoji-menu');
- $('.emoji-search').click();
-
- expect($emojiMenu.length).toBe(1);
- expect($emojiMenu.hasClass('is-visible')).toBe(true);
- expect($('.js-awards-block.current').length).toBe(1);
- });
- });
- });
-
- describe('::addAwardToEmojiBar', function() {
- it('should add emoji to votes block', function() {
- const $votesBlock = $('.js-awards-block').eq(0);
- awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
- const $emojiButton = $votesBlock.find('[data-name=heart]');
-
- expect($emojiButton.length).toBe(1);
- expect($emojiButton.next('.js-counter').text()).toBe('1');
- expect($votesBlock.hasClass('hidden')).toBe(false);
- });
-
- it('should remove the emoji when we click again', function() {
- const $votesBlock = $('.js-awards-block').eq(0);
- awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
- awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
- const $emojiButton = $votesBlock.find('[data-name=heart]');
-
- expect($emojiButton.length).toBe(0);
- });
-
- it('should decrement the emoji counter', function() {
- const $votesBlock = $('.js-awards-block').eq(0);
- awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
- const $emojiButton = $votesBlock.find('[data-name=heart]');
- $emojiButton.next('.js-counter').text(5);
- awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
-
- expect($emojiButton.length).toBe(1);
- expect($emojiButton.next('.js-counter').text()).toBe('4');
- });
- });
-
- describe('::userAuthored', function() {
- it('should update tooltip to user authored title', function() {
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'sam');
- awardsHandler.userAuthored($thumbsUpEmoji);
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe(
- 'You cannot vote on your own issue, MR and note',
- );
- });
-
- it('should restore tooltip back to initial vote list', function() {
- jasmine.clock().install();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'sam');
- awardsHandler.userAuthored($thumbsUpEmoji);
- jasmine.clock().tick(2801);
- jasmine.clock().uninstall();
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
- });
- });
-
- describe('::getAwardUrl', function() {
- it('returns the url for request', function() {
- expect(awardsHandler.getAwardUrl()).toBe('http://test.host/snippets/1/toggle_award_emoji');
- });
- });
-
- describe('::addAward and ::checkMutuality', function() {
- it('should handle :+1: and :-1: mutuality', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- const $thumbsDownEmoji = $votesBlock.find('[data-name=thumbsdown]').parent();
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
-
- expect($thumbsUpEmoji.hasClass('active')).toBe(true);
- expect($thumbsDownEmoji.hasClass('active')).toBe(false);
- $thumbsUpEmoji.tooltip();
- $thumbsDownEmoji.tooltip();
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsdown', true);
-
- expect($thumbsUpEmoji.hasClass('active')).toBe(false);
- expect($thumbsDownEmoji.hasClass('active')).toBe(true);
- });
- });
-
- describe('::removeEmoji', function() {
- it('should remove emoji', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- awardsHandler.addAward($votesBlock, awardUrl, 'fire', false);
-
- expect($votesBlock.find('[data-name=fire]').length).toBe(1);
- awardsHandler.removeEmoji($votesBlock.find('[data-name=fire]').closest('button'));
-
- expect($votesBlock.find('[data-name=fire]').length).toBe(0);
- });
- });
-
- describe('::addYouToUserList', function() {
- it('should prepend "You" to the award tooltip', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'sam, jerry, max, and andy');
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
- $thumbsUpEmoji.tooltip();
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe('You, sam, jerry, max, and andy');
- });
-
- it('handles the special case where "You" is not cleanly comma separated', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'sam');
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
- $thumbsUpEmoji.tooltip();
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe('You and sam');
- });
- });
-
- describe('::removeYouToUserList', function() {
- it('removes "You" from the front of the tooltip', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'You, sam, jerry, max, and andy');
- $thumbsUpEmoji.addClass('active');
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
- $thumbsUpEmoji.tooltip();
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe('sam, jerry, max, and andy');
- });
-
- it('handles the special case where "You" is not cleanly comma separated', function() {
- const awardUrl = awardsHandler.getAwardUrl();
- const $votesBlock = $('.js-awards-block').eq(0);
- const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
- $thumbsUpEmoji.attr('data-title', 'You and sam');
- $thumbsUpEmoji.addClass('active');
- awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false);
- $thumbsUpEmoji.tooltip();
-
- expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
- });
- });
-
- describe('::searchEmojis', () => {
- it('should filter the emoji', function(done) {
- openAndWaitForEmojiMenu()
- .then(() => {
- expect($('[data-name=angel]').is(':visible')).toBe(true);
- expect($('[data-name=anger]').is(':visible')).toBe(true);
- awardsHandler.searchEmojis('ali');
-
- expect($('[data-name=angel]').is(':visible')).toBe(false);
- expect($('[data-name=anger]').is(':visible')).toBe(false);
- expect($('[data-name=alien]').is(':visible')).toBe(true);
- expect($('.js-emoji-menu-search').val()).toBe('ali');
- })
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
-
- it('should clear the search when searching for nothing', function(done) {
- openAndWaitForEmojiMenu()
- .then(() => {
- awardsHandler.searchEmojis('ali');
-
- expect($('[data-name=angel]').is(':visible')).toBe(false);
- expect($('[data-name=anger]').is(':visible')).toBe(false);
- expect($('[data-name=alien]').is(':visible')).toBe(true);
- awardsHandler.searchEmojis('');
-
- expect($('[data-name=angel]').is(':visible')).toBe(true);
- expect($('[data-name=anger]').is(':visible')).toBe(true);
- expect($('[data-name=alien]').is(':visible')).toBe(true);
- expect($('.js-emoji-menu-search').val()).toBe('');
- })
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
- });
-
- describe('emoji menu', function() {
- const emojiSelector = '[data-name="sunglasses"]';
- const openEmojiMenuAndAddEmoji = function() {
- return openAndWaitForEmojiMenu().then(() => {
- const $menu = $('.emoji-menu');
- const $block = $('.js-awards-block');
- const $emoji = $menu.find(`.emoji-menu-list:not(.frequent-emojis) ${emojiSelector}`);
-
- expect($emoji.length).toBe(1);
- expect($block.find(emojiSelector).length).toBe(0);
- $emoji.click();
-
- expect($menu.hasClass('.is-visible')).toBe(false);
- expect($block.find(emojiSelector).length).toBe(1);
- });
- };
-
- it('should add selected emoji to awards block', function(done) {
- openEmojiMenuAndAddEmoji()
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
-
- it('should remove already selected emoji', function(done) {
- openEmojiMenuAndAddEmoji()
- .then(() => {
- $('.js-add-award')
- .eq(0)
- .click();
- const $block = $('.js-awards-block');
- const $emoji = $('.emoji-menu').find(
- `.emoji-menu-list:not(.frequent-emojis) ${emojiSelector}`,
- );
- $emoji.click();
-
- expect($block.find(emojiSelector).length).toBe(0);
- })
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
- });
-
- describe('frequently used emojis', function() {
- beforeEach(() => {
- // Clear it out
- Cookies.set('frequently_used_emojis', '');
- });
-
- it('shouldn\'t have any "Frequently used" heading if no frequently used emojis', function(done) {
- return openAndWaitForEmojiMenu()
- .then(() => {
- const emojiMenu = document.querySelector('.emoji-menu');
- Array.prototype.forEach.call(emojiMenu.querySelectorAll('.emoji-menu-title'), title => {
- expect(title.textContent.trim().toLowerCase()).not.toBe('frequently used');
- });
- })
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
-
- it('should have any frequently used section when there are frequently used emojis', function(done) {
- awardsHandler.addEmojiToFrequentlyUsedList('8ball');
-
- return openAndWaitForEmojiMenu()
- .then(() => {
- const emojiMenu = document.querySelector('.emoji-menu');
- const hasFrequentlyUsedHeading = Array.prototype.some.call(
- emojiMenu.querySelectorAll('.emoji-menu-title'),
- title => title.textContent.trim().toLowerCase() === 'frequently used',
- );
-
- expect(hasFrequentlyUsedHeading).toBe(true);
- })
- .then(done)
- .catch(err => {
- done.fail(`Failed to open and build emoji menu: ${err.message}`);
- });
- });
-
- it('should disregard invalid frequently used emoji that are being attempted to be added', function() {
- awardsHandler.addEmojiToFrequentlyUsedList('8ball');
- awardsHandler.addEmojiToFrequentlyUsedList('invalid_emoji');
- awardsHandler.addEmojiToFrequentlyUsedList('grinning');
-
- expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
- });
-
- it('should disregard invalid frequently used emoji already set in cookie', function() {
- Cookies.set('frequently_used_emojis', '8ball,invalid_emoji,grinning');
-
- expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
- });
- });
-});
diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js
deleted file mode 100644
index 59abae479d4..00000000000
--- a/spec/javascripts/behaviors/autosize_spec.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import $ from 'jquery';
-import '~/behaviors/autosize';
-
-function load() {
- $(document).trigger('load');
-}
-
-describe('Autosize behavior', () => {
- beforeEach(() => {
- setFixtures('<textarea class="js-autosize" style="resize: vertical"></textarea>');
- });
-
- it('does not overwrite the resize property', () => {
- load();
-
- expect($('textarea')).toHaveCss({
- resize: 'vertical',
- });
- });
-});
diff --git a/spec/javascripts/behaviors/copy_as_gfm_spec.js b/spec/javascripts/behaviors/copy_as_gfm_spec.js
deleted file mode 100644
index d653fca0988..00000000000
--- a/spec/javascripts/behaviors/copy_as_gfm_spec.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import initCopyAsGFM, { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm';
-
-describe('CopyAsGFM', () => {
- describe('CopyAsGFM.pasteGFM', () => {
- function callPasteGFM() {
- const e = {
- originalEvent: {
- clipboardData: {
- getData(mimeType) {
- // When GFM code is copied, we put the regular plain text
- // on the clipboard as `text/plain`, and the GFM as `text/x-gfm`.
- // This emulates the behavior of `getData` with that data.
- if (mimeType === 'text/plain') {
- return 'code';
- }
- if (mimeType === 'text/x-gfm') {
- return '`code`';
- }
- return null;
- },
- },
- },
- preventDefault() {},
- };
-
- CopyAsGFM.pasteGFM(e);
- }
-
- it('wraps pasted code when not already in code tags', () => {
- spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
- const insertedText = textFunc('This is code: ', '');
-
- expect(insertedText).toEqual('`code`');
- });
-
- callPasteGFM();
- });
-
- it('does not wrap pasted code when already in code tags', () => {
- spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
- const insertedText = textFunc('This is code: `', '`');
-
- expect(insertedText).toEqual('code');
- });
-
- callPasteGFM();
- });
- });
-
- describe('CopyAsGFM.copyGFM', () => {
- // Stub getSelection to return a purpose-built object.
- const stubSelection = (html, parentNode) => ({
- getRangeAt: () => ({
- commonAncestorContainer: { tagName: parentNode },
- cloneContents: () => {
- const fragment = document.createDocumentFragment();
- const node = document.createElement('div');
- node.innerHTML = html;
- Array.from(node.childNodes).forEach(item => fragment.appendChild(item));
- return fragment;
- },
- }),
- rangeCount: 1,
- });
-
- const clipboardData = {
- setData() {},
- };
-
- const simulateCopy = () => {
- const e = {
- originalEvent: {
- clipboardData,
- },
- preventDefault() {},
- stopPropagation() {},
- };
- CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection);
- return clipboardData;
- };
-
- beforeAll(done => {
- initCopyAsGFM();
-
- // Fake call to nodeToGfm so the import of lazy bundle happened
- CopyAsGFM.nodeToGFM(document.createElement('div'))
- .then(() => {
- done();
- })
- .catch(done.fail);
- });
-
- beforeEach(() => spyOn(clipboardData, 'setData'));
-
- describe('list handling', () => {
- it('uses correct gfm for unordered lists', done => {
- const selection = stubSelection('<li>List Item1</li><li>List Item2</li>\n', 'UL');
-
- spyOn(window, 'getSelection').and.returnValue(selection);
- simulateCopy();
-
- setTimeout(() => {
- const expectedGFM = '* List Item1\n* List Item2';
-
- expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
- done();
- });
- });
-
- it('uses correct gfm for ordered lists', done => {
- const selection = stubSelection('<li>List Item1</li><li>List Item2</li>\n', 'OL');
-
- spyOn(window, 'getSelection').and.returnValue(selection);
- simulateCopy();
-
- setTimeout(() => {
- const expectedGFM = '1. List Item1\n1. List Item2';
-
- expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
- done();
- });
- });
- });
- });
-});
diff --git a/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js b/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
deleted file mode 100644
index f656b97fec2..00000000000
--- a/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import getUnicodeSupportMap from '~/emoji/support/unicode_support_map';
-import AccessorUtilities from '~/lib/utils/accessor';
-
-describe('Unicode Support Map', () => {
- describe('getUnicodeSupportMap', () => {
- const stringSupportMap = 'stringSupportMap';
-
- beforeEach(() => {
- spyOn(AccessorUtilities, 'isLocalStorageAccessSafe');
- spyOn(window.localStorage, 'getItem');
- spyOn(window.localStorage, 'setItem');
- spyOn(JSON, 'parse');
- spyOn(JSON, 'stringify').and.returnValue(stringSupportMap);
- });
-
- describe('if isLocalStorageAvailable is `true`', function() {
- beforeEach(() => {
- AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(true);
-
- getUnicodeSupportMap();
- });
-
- it('should call .getItem and .setItem', () => {
- const getArgs = window.localStorage.getItem.calls.allArgs();
- const setArgs = window.localStorage.setItem.calls.allArgs();
-
- expect(getArgs[0][0]).toBe('gl-emoji-version');
- expect(getArgs[1][0]).toBe('gl-emoji-user-agent');
-
- expect(setArgs[0][0]).toBe('gl-emoji-version');
- expect(setArgs[0][1]).toBe('0.2.0');
- expect(setArgs[1][0]).toBe('gl-emoji-user-agent');
- expect(setArgs[1][1]).toBe(navigator.userAgent);
- expect(setArgs[2][0]).toBe('gl-emoji-unicode-support-map');
- expect(setArgs[2][1]).toBe(stringSupportMap);
- });
- });
-
- describe('if isLocalStorageAvailable is `false`', function() {
- beforeEach(() => {
- AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(false);
-
- getUnicodeSupportMap();
- });
-
- it('should not call .getItem or .setItem', () => {
- expect(window.localStorage.getItem.calls.count()).toBe(1);
- expect(window.localStorage.setItem).not.toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/spec/javascripts/behaviors/markdown/highlight_current_user_spec.js b/spec/javascripts/behaviors/markdown/highlight_current_user_spec.js
deleted file mode 100644
index 3305ddc412d..00000000000
--- a/spec/javascripts/behaviors/markdown/highlight_current_user_spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
-
-describe('highlightCurrentUser', () => {
- let rootElement;
- let elements;
-
- beforeEach(() => {
- setFixtures(`
- <div id="dummy-root-element">
- <div data-user="1">@first</div>
- <div data-user="2">@second</div>
- </div>
- `);
- rootElement = document.getElementById('dummy-root-element');
- elements = rootElement.querySelectorAll('[data-user]');
- });
-
- describe('without current user', () => {
- beforeEach(() => {
- window.gon = window.gon || {};
- window.gon.current_user_id = null;
- });
-
- afterEach(() => {
- delete window.gon.current_user_id;
- });
-
- it('does not highlight the user', () => {
- const initialHtml = rootElement.outerHTML;
-
- highlightCurrentUser(elements);
-
- expect(rootElement.outerHTML).toBe(initialHtml);
- });
- });
-
- describe('with current user', () => {
- beforeEach(() => {
- window.gon = window.gon || {};
- window.gon.current_user_id = 2;
- });
-
- afterEach(() => {
- delete window.gon.current_user_id;
- });
-
- it('highlights current user', () => {
- highlightCurrentUser(elements);
-
- expect(elements.length).toBe(2);
- expect(elements[0]).not.toHaveClass('current-user');
- expect(elements[1]).toHaveClass('current-user');
- });
- });
-});
diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js
deleted file mode 100644
index 617fe49b059..00000000000
--- a/spec/javascripts/behaviors/requires_input_spec.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import $ from 'jquery';
-import '~/behaviors/requires_input';
-
-describe('requiresInput', () => {
- let submitButton;
- preloadFixtures('branches/new_branch.html');
-
- beforeEach(() => {
- loadFixtures('branches/new_branch.html');
- submitButton = $('button[type="submit"]');
- });
-
- it('disables submit when any field is required', () => {
- $('.js-requires-input').requiresInput();
-
- expect(submitButton).toBeDisabled();
- });
-
- it('enables submit when no field is required', () => {
- $('*[required=required]').prop('required', false);
- $('.js-requires-input').requiresInput();
-
- expect(submitButton).not.toBeDisabled();
- });
-
- it('enables submit when all required fields are pre-filled', () => {
- $('*[required=required]').remove();
- $('.js-requires-input').requiresInput();
-
- expect($('.submit')).not.toBeDisabled();
- });
-
- it('enables submit when all required fields receive input', () => {
- $('.js-requires-input').requiresInput();
- $('#required1')
- .val('input1')
- .change();
-
- expect(submitButton).toBeDisabled();
-
- $('#optional1')
- .val('input1')
- .change();
-
- expect(submitButton).toBeDisabled();
-
- $('#required2')
- .val('input2')
- .change();
- $('#required3')
- .val('input3')
- .change();
- $('#required4')
- .val('input4')
- .change();
- $('#required5')
- .val('1')
- .change();
-
- expect($('.submit')).not.toBeDisabled();
- });
-});
diff --git a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
deleted file mode 100644
index f6232026915..00000000000
--- a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
+++ /dev/null
@@ -1,315 +0,0 @@
-/* eslint-disable
- no-underscore-dangle
-*/
-
-import $ from 'jquery';
-import initCopyAsGFM, { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm';
-import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
-
-const FORM_SELECTOR = '.js-main-target-form .js-vue-comment-form';
-
-describe('ShortcutsIssuable', function() {
- const fixtureName = 'snippets/show.html';
- preloadFixtures(fixtureName);
-
- beforeAll(done => {
- initCopyAsGFM();
-
- // Fake call to nodeToGfm so the import of lazy bundle happened
- CopyAsGFM.nodeToGFM(document.createElement('div'))
- .then(() => {
- done();
- })
- .catch(done.fail);
- });
-
- beforeEach(() => {
- loadFixtures(fixtureName);
- $('body').append(
- `<div class="js-main-target-form">
- <textare class="js-vue-comment-form"></textare>
- </div>`,
- );
- document.querySelector('.js-new-note-form').classList.add('js-main-target-form');
- this.shortcut = new ShortcutsIssuable(true);
- });
-
- afterEach(() => {
- $(FORM_SELECTOR).remove();
- });
-
- describe('replyWithSelectedText', () => {
- // Stub window.gl.utils.getSelectedFragment to return a node with the provided HTML.
- const stubSelection = (html, invalidNode) => {
- ShortcutsIssuable.__Rewire__('getSelectedFragment', () => {
- const documentFragment = document.createDocumentFragment();
- const node = document.createElement('div');
-
- node.innerHTML = html;
- if (!invalidNode) node.className = 'md';
-
- documentFragment.appendChild(node);
- return documentFragment;
- });
- };
-
- describe('with empty selection', () => {
- it('does not return an error', () => {
- ShortcutsIssuable.replyWithSelectedText(true);
-
- expect($(FORM_SELECTOR).val()).toBe('');
- });
-
- it('triggers `focus`', () => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- expect(spy).toHaveBeenCalled();
- });
- });
-
- describe('with any selection', () => {
- beforeEach(() => {
- stubSelection('<p>Selected text.</p>');
- });
-
- it('leaves existing input intact', done => {
- $(FORM_SELECTOR).val('This text was already here.');
-
- expect($(FORM_SELECTOR).val()).toBe('This text was already here.');
-
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe(
- 'This text was already here.\n\n> Selected text.\n\n',
- );
- done();
- });
- });
-
- it('triggers `input`', done => {
- let triggered = false;
- $(FORM_SELECTOR).on('input', () => {
- triggered = true;
- });
-
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(triggered).toBe(true);
- done();
- });
- });
-
- it('triggers `focus`', done => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
- });
-
- describe('with a one-line selection', () => {
- it('quotes the selection', done => {
- stubSelection('<p>This text has been selected.</p>');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('> This text has been selected.\n\n');
- done();
- });
- });
- });
-
- describe('with a multi-line selection', () => {
- it('quotes the selected lines as a group', done => {
- stubSelection(
- '<p>Selected line one.</p>\n<p>Selected line two.</p>\n<p>Selected line three.</p>',
- );
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe(
- '> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n',
- );
- done();
- });
- });
- });
-
- describe('with an invalid selection', () => {
- beforeEach(() => {
- stubSelection('<p>Selected text.</p>', true);
- });
-
- it('does not add anything to the input', done => {
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('');
- done();
- });
- });
-
- it('triggers `focus`', done => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
- });
-
- describe('with a semi-valid selection', () => {
- beforeEach(() => {
- stubSelection('<div class="md">Selected text.</div><p>Invalid selected text.</p>', true);
- });
-
- it('only adds the valid part to the input', done => {
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('> Selected text.\n\n');
- done();
- });
- });
-
- it('triggers `focus`', done => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
-
- it('triggers `input`', done => {
- let triggered = false;
- $(FORM_SELECTOR).on('input', () => {
- triggered = true;
- });
-
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(triggered).toBe(true);
- done();
- });
- });
- });
-
- describe('with a selection in a valid block', () => {
- beforeEach(() => {
- ShortcutsIssuable.__Rewire__('getSelectedFragment', () => {
- const documentFragment = document.createDocumentFragment();
- const node = document.createElement('div');
- const originalNode = document.createElement('body');
- originalNode.innerHTML = `<div class="issue">
- <div class="otherElem">Text...</div>
- <div class="md"><p><em>Selected text.</em></p></div>
- </div>`;
- documentFragment.originalNodes = [originalNode.querySelector('em')];
-
- node.innerHTML = '<em>Selected text.</em>';
-
- documentFragment.appendChild(node);
-
- return documentFragment;
- });
- });
-
- it('adds the quoted selection to the input', done => {
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('> *Selected text.*\n\n');
- done();
- });
- });
-
- it('triggers `focus`', done => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
-
- it('triggers `input`', done => {
- let triggered = false;
- $(FORM_SELECTOR).on('input', () => {
- triggered = true;
- });
-
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(triggered).toBe(true);
- done();
- });
- });
- });
-
- describe('with a selection in an invalid block', () => {
- beforeEach(() => {
- ShortcutsIssuable.__Rewire__('getSelectedFragment', () => {
- const documentFragment = document.createDocumentFragment();
- const node = document.createElement('div');
- const originalNode = document.createElement('body');
- originalNode.innerHTML = `<div class="issue">
- <div class="otherElem"><div><b>Selected text.</b></div></div>
- <div class="md"><p><em>Valid text</em></p></div>
- </div>`;
- documentFragment.originalNodes = [originalNode.querySelector('b')];
-
- node.innerHTML = '<b>Selected text.</b>';
-
- documentFragment.appendChild(node);
-
- return documentFragment;
- });
- });
-
- it('does not add anything to the input', done => {
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('');
- done();
- });
- });
-
- it('triggers `focus`', done => {
- const spy = spyOn(document.querySelector(FORM_SELECTOR), 'focus');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
- });
-
- describe('with a valid selection with no text content', () => {
- it('returns the proper markdown', done => {
- stubSelection('<img src="foo" alt="image" />');
- ShortcutsIssuable.replyWithSelectedText(true);
-
- setTimeout(() => {
- expect($(FORM_SELECTOR).val()).toBe('> ![image](http://localhost:9876/foo)\n\n');
-
- done();
- });
- });
- });
- });
-});
diff --git a/spec/javascripts/boards/board_list_common_spec.js b/spec/javascripts/boards/board_list_common_spec.js
deleted file mode 100644
index b51a82f2a35..00000000000
--- a/spec/javascripts/boards/board_list_common_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/* global List */
-/* global ListIssue */
-
-import MockAdapter from 'axios-mock-adapter';
-import Vue from 'vue';
-import Sortable from 'sortablejs';
-import axios from '~/lib/utils/axios_utils';
-import BoardList from '~/boards/components/board_list.vue';
-
-import '~/boards/models/issue';
-import '~/boards/models/list';
-import { listObj, boardsMockInterceptor } from './mock_data';
-import store from '~/boards/stores';
-import boardsStore from '~/boards/stores/boards_store';
-
-window.Sortable = Sortable;
-
-export default function createComponent({
- done,
- listIssueProps = {},
- componentProps = {},
- listProps = {},
-}) {
- const el = document.createElement('div');
-
- document.body.appendChild(el);
- const mock = new MockAdapter(axios);
- mock.onAny().reply(boardsMockInterceptor);
- boardsStore.create();
-
- const BoardListComp = Vue.extend(BoardList);
- const list = new List({ ...listObj, ...listProps });
- const issue = new ListIssue({
- title: 'Testing',
- id: 1,
- iid: 1,
- confidential: false,
- labels: [],
- assignees: [],
- ...listIssueProps,
- });
- if (!Object.prototype.hasOwnProperty.call(listProps, 'issuesSize')) {
- list.issuesSize = 1;
- }
- list.issues.push(issue);
-
- const component = new BoardListComp({
- el,
- store,
- propsData: {
- disabled: false,
- list,
- issues: list.issues,
- loading: false,
- issueLinkBase: '/issues',
- rootPath: '/',
- ...componentProps,
- },
- }).$mount();
-
- Vue.nextTick(() => {
- done();
- });
-
- return { component, mock };
-}
diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js
deleted file mode 100644
index f2eb08fa198..00000000000
--- a/spec/javascripts/collapsed_sidebar_todo_spec.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/* eslint-disable no-new */
-import { clone } from 'lodash';
-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';
- const jsonFixtureName = 'todos/todos.json';
- let mock;
-
- preloadFixtures(fixtureName);
- preloadFixtures(jsonFixtureName);
-
- beforeEach(() => {
- const todoData = getJSONFixture(jsonFixtureName);
- new Sidebar();
- loadFixtures(fixtureName);
-
- document.querySelector('.js-right-sidebar').classList.toggle('right-sidebar-expanded');
- document.querySelector('.js-right-sidebar').classList.toggle('right-sidebar-collapsed');
-
- mock = new MockAdapter(axios);
-
- mock.onPost(`${gl.TEST_HOST}/frontend-fixtures/issues-project/todos`).reply(() => {
- const response = clone(todoData);
-
- return [200, response];
- });
-
- 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')).not.toBeNull();
-
- expect(
- document
- .querySelector('.js-issuable-todo.sidebar-collapsed-icon svg use')
- .getAttribute('xlink:href'),
- ).toContain('todo-add');
-
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
- ).toBeNull();
- });
-
- it('sets default tooltip title', () => {
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('title'),
- ).toBe('Add a To Do');
- });
-
- it('toggle todo state', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- setTimeout(() => {
- expect(
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
- ).not.toBeNull();
-
- expect(
- document
- .querySelector('.js-issuable-todo.sidebar-collapsed-icon svg.todo-undone use')
- .getAttribute('xlink:href'),
- ).toContain('todo-done');
-
- done();
- });
- });
-
- it('toggle todo state of expanded todo toggle', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- setTimeout(() => {
- expect(
- document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Mark as done');
-
- done();
- });
- });
-
- it('toggles todo button tooltip', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- setTimeout(() => {
- expect(
- document
- .querySelector('.js-issuable-todo.sidebar-collapsed-icon')
- .getAttribute('data-original-title'),
- ).toBe('Mark as done');
-
- done();
- });
- });
-
- it('marks todo as done', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- 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 a To Do');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('updates aria-label to Mark as done', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- setTimeout(() => {
- expect(
- document
- .querySelector('.js-issuable-todo.sidebar-collapsed-icon')
- .getAttribute('aria-label'),
- ).toBe('Mark as done');
-
- done();
- });
- });
-
- it('updates aria-label to add todo', done => {
- document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
-
- timeoutPromise()
- .then(() => {
- expect(
- document
- .querySelector('.js-issuable-todo.sidebar-collapsed-icon')
- .getAttribute('aria-label'),
- ).toBe('Mark as 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 a To Do');
- })
- .then(done)
- .catch(done.fail);
- });
-});
diff --git a/spec/javascripts/comment_type_toggle_spec.js b/spec/javascripts/comment_type_toggle_spec.js
deleted file mode 100644
index 8b1217a000f..00000000000
--- a/spec/javascripts/comment_type_toggle_spec.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import CommentTypeToggle from '~/comment_type_toggle';
-import InputSetter from '~/droplab/plugins/input_setter';
-
-describe('CommentTypeToggle', function() {
- describe('class constructor', function() {
- beforeEach(function() {
- this.dropdownTrigger = {};
- this.dropdownList = {};
- this.noteTypeInput = {};
- this.submitButton = {};
- this.closeButton = {};
-
- this.commentTypeToggle = new CommentTypeToggle({
- dropdownTrigger: this.dropdownTrigger,
- dropdownList: this.dropdownList,
- noteTypeInput: this.noteTypeInput,
- submitButton: this.submitButton,
- closeButton: this.closeButton,
- });
- });
-
- it('should set .dropdownTrigger', function() {
- expect(this.commentTypeToggle.dropdownTrigger).toBe(this.dropdownTrigger);
- });
-
- it('should set .dropdownList', function() {
- expect(this.commentTypeToggle.dropdownList).toBe(this.dropdownList);
- });
-
- it('should set .noteTypeInput', function() {
- expect(this.commentTypeToggle.noteTypeInput).toBe(this.noteTypeInput);
- });
-
- it('should set .submitButton', function() {
- expect(this.commentTypeToggle.submitButton).toBe(this.submitButton);
- });
-
- it('should set .closeButton', function() {
- expect(this.commentTypeToggle.closeButton).toBe(this.closeButton);
- });
-
- it('should set .reopenButton', function() {
- expect(this.commentTypeToggle.reopenButton).toBe(this.reopenButton);
- });
- });
-
- describe('initDroplab', function() {
- beforeEach(function() {
- this.commentTypeToggle = {
- dropdownTrigger: {},
- dropdownList: {},
- noteTypeInput: {},
- submitButton: {},
- closeButton: {},
- setConfig: () => {},
- };
- this.config = {};
-
- this.droplab = jasmine.createSpyObj('droplab', ['init']);
-
- this.droplabConstructor = spyOnDependency(CommentTypeToggle, 'DropLab').and.returnValue(
- this.droplab,
- );
- spyOn(this.commentTypeToggle, 'setConfig').and.returnValue(this.config);
-
- CommentTypeToggle.prototype.initDroplab.call(this.commentTypeToggle);
- });
-
- it('should instantiate a DropLab instance', function() {
- expect(this.droplabConstructor).toHaveBeenCalled();
- });
-
- it('should set .droplab', function() {
- expect(this.commentTypeToggle.droplab).toBe(this.droplab);
- });
-
- it('should call .setConfig', function() {
- expect(this.commentTypeToggle.setConfig).toHaveBeenCalled();
- });
-
- it('should call DropLab.prototype.init', function() {
- expect(this.droplab.init).toHaveBeenCalledWith(
- this.commentTypeToggle.dropdownTrigger,
- this.commentTypeToggle.dropdownList,
- [InputSetter],
- this.config,
- );
- });
- });
-
- describe('setConfig', function() {
- describe('if no .closeButton is provided', function() {
- beforeEach(function() {
- this.commentTypeToggle = {
- dropdownTrigger: {},
- dropdownList: {},
- noteTypeInput: {},
- submitButton: {},
- reopenButton: {},
- };
-
- this.setConfig = CommentTypeToggle.prototype.setConfig.call(this.commentTypeToggle);
- });
-
- it('should not add .closeButton related InputSetter config', function() {
- expect(this.setConfig).toEqual({
- InputSetter: [
- {
- input: this.commentTypeToggle.noteTypeInput,
- valueAttribute: 'data-value',
- },
- {
- input: this.commentTypeToggle.submitButton,
- valueAttribute: 'data-submit-text',
- },
- {
- input: this.commentTypeToggle.reopenButton,
- valueAttribute: 'data-reopen-text',
- },
- {
- input: this.commentTypeToggle.reopenButton,
- valueAttribute: 'data-reopen-text',
- inputAttribute: 'data-alternative-text',
- },
- ],
- });
- });
- });
-
- describe('if no .reopenButton is provided', function() {
- beforeEach(function() {
- this.commentTypeToggle = {
- dropdownTrigger: {},
- dropdownList: {},
- noteTypeInput: {},
- submitButton: {},
- closeButton: {},
- };
-
- this.setConfig = CommentTypeToggle.prototype.setConfig.call(this.commentTypeToggle);
- });
-
- it('should not add .reopenButton related InputSetter config', function() {
- expect(this.setConfig).toEqual({
- InputSetter: [
- {
- input: this.commentTypeToggle.noteTypeInput,
- valueAttribute: 'data-value',
- },
- {
- input: this.commentTypeToggle.submitButton,
- valueAttribute: 'data-submit-text',
- },
- {
- input: this.commentTypeToggle.closeButton,
- valueAttribute: 'data-close-text',
- },
- {
- input: this.commentTypeToggle.closeButton,
- valueAttribute: 'data-close-text',
- inputAttribute: 'data-alternative-text',
- },
- ],
- });
- });
- });
- });
-});
diff --git a/spec/javascripts/droplab/drop_down_spec.js b/spec/javascripts/droplab/drop_down_spec.js
deleted file mode 100644
index 22346c10547..00000000000
--- a/spec/javascripts/droplab/drop_down_spec.js
+++ /dev/null
@@ -1,650 +0,0 @@
-import DropDown from '~/droplab/drop_down';
-import utils from '~/droplab/utils';
-import { SELECTED_CLASS } from '~/droplab/constants';
-
-describe('DropLab DropDown', function() {
- describe('class constructor', function() {
- beforeEach(function() {
- spyOn(DropDown.prototype, 'getItems');
- spyOn(DropDown.prototype, 'initTemplateString');
- spyOn(DropDown.prototype, 'addEvents');
-
- this.list = { innerHTML: 'innerHTML' };
- this.dropdown = new DropDown(this.list);
- });
-
- it('sets the .hidden property to true', function() {
- expect(this.dropdown.hidden).toBe(true);
- });
-
- it('sets the .list property', function() {
- expect(this.dropdown.list).toBe(this.list);
- });
-
- it('calls .getItems', function() {
- expect(DropDown.prototype.getItems).toHaveBeenCalled();
- });
-
- it('calls .initTemplateString', function() {
- expect(DropDown.prototype.initTemplateString).toHaveBeenCalled();
- });
-
- it('calls .addEvents', function() {
- expect(DropDown.prototype.addEvents).toHaveBeenCalled();
- });
-
- it('sets the .initialState property to the .list.innerHTML', function() {
- expect(this.dropdown.initialState).toBe(this.list.innerHTML);
- });
-
- describe('if the list argument is a string', function() {
- beforeEach(function() {
- this.element = {};
- this.selector = '.selector';
-
- spyOn(Document.prototype, 'querySelector').and.returnValue(this.element);
-
- this.dropdown = new DropDown(this.selector);
- });
-
- it('calls .querySelector with the selector string', function() {
- expect(Document.prototype.querySelector).toHaveBeenCalledWith(this.selector);
- });
-
- it('sets the .list property element', function() {
- expect(this.dropdown.list).toBe(this.element);
- });
- });
- });
-
- describe('getItems', function() {
- beforeEach(function() {
- this.list = { querySelectorAll: () => {} };
- this.dropdown = { list: this.list };
- this.nodeList = [];
-
- spyOn(this.list, 'querySelectorAll').and.returnValue(this.nodeList);
-
- this.getItems = DropDown.prototype.getItems.call(this.dropdown);
- });
-
- it('calls .querySelectorAll with a list item query', function() {
- expect(this.list.querySelectorAll).toHaveBeenCalledWith('li');
- });
-
- it('sets the .items property to the returned list items', function() {
- expect(this.dropdown.items).toEqual(jasmine.any(Array));
- });
-
- it('returns the .items', function() {
- expect(this.getItems).toEqual(jasmine.any(Array));
- });
- });
-
- describe('initTemplateString', function() {
- beforeEach(function() {
- this.items = [{ outerHTML: '<a></a>' }, { outerHTML: '<img>' }];
- this.dropdown = { items: this.items };
-
- DropDown.prototype.initTemplateString.call(this.dropdown);
- });
-
- it('should set .templateString to the last items .outerHTML', function() {
- expect(this.dropdown.templateString).toBe(this.items[1].outerHTML);
- });
-
- it('should not set .templateString to a non-last items .outerHTML', function() {
- expect(this.dropdown.templateString).not.toBe(this.items[0].outerHTML);
- });
-
- describe('if .items is not set', function() {
- beforeEach(function() {
- this.dropdown = { getItems: () => {} };
-
- spyOn(this.dropdown, 'getItems').and.returnValue([]);
-
- DropDown.prototype.initTemplateString.call(this.dropdown);
- });
-
- it('should call .getItems', function() {
- expect(this.dropdown.getItems).toHaveBeenCalled();
- });
- });
-
- describe('if items array is empty', function() {
- beforeEach(function() {
- this.dropdown = { items: [] };
-
- DropDown.prototype.initTemplateString.call(this.dropdown);
- });
-
- it('should set .templateString to an empty string', function() {
- expect(this.dropdown.templateString).toBe('');
- });
- });
- });
-
- describe('clickEvent', function() {
- beforeEach(function() {
- this.classList = jasmine.createSpyObj('classList', ['contains']);
- this.list = { dispatchEvent: () => {} };
- this.dropdown = {
- hideOnClick: true,
- hide: () => {},
- list: this.list,
- addSelectedClass: () => {},
- };
- this.event = {
- preventDefault: () => {},
- target: {
- classList: this.classList,
- closest: () => null,
- },
- };
- this.customEvent = {};
- this.dummyListItem = document.createElement('li');
- spyOn(this.event.target, 'closest').and.callFake(selector => {
- if (selector === 'li') {
- return this.dummyListItem;
- }
-
- return null;
- });
-
- spyOn(this.dropdown, 'hide');
- spyOn(this.dropdown, 'addSelectedClass');
- spyOn(this.list, 'dispatchEvent');
- spyOn(this.event, 'preventDefault');
- spyOn(window, 'CustomEvent').and.returnValue(this.customEvent);
- this.classList.contains.and.returnValue(false);
- });
-
- it('should call event.target.closest', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.event.target.closest).toHaveBeenCalledWith('.droplab-item-ignore');
- expect(this.event.target.closest).toHaveBeenCalledWith('li');
- });
-
- it('should call addSelectedClass', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.dropdown.addSelectedClass).toHaveBeenCalledWith(this.dummyListItem);
- });
-
- it('should call .preventDefault', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.event.preventDefault).toHaveBeenCalled();
- });
-
- it('should call .hide', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.dropdown.hide).toHaveBeenCalled();
- });
-
- it('should construct CustomEvent', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(window.CustomEvent).toHaveBeenCalledWith('click.dl', jasmine.any(Object));
- });
-
- it('should call .dispatchEvent with the customEvent', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.list.dispatchEvent).toHaveBeenCalledWith(this.customEvent);
- });
-
- describe('if the target is a UL element', function() {
- beforeEach(function() {
- this.event.target = document.createElement('ul');
-
- spyOn(this.event.target, 'closest');
- });
-
- it('should return immediately', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.event.target.closest).not.toHaveBeenCalled();
- expect(this.dropdown.addSelectedClass).not.toHaveBeenCalled();
- });
- });
-
- describe('if the target has the droplab-item-ignore class', function() {
- beforeEach(function() {
- this.ignoredButton = document.createElement('button');
- this.ignoredButton.classList.add('droplab-item-ignore');
- this.event.target = this.ignoredButton;
-
- spyOn(this.ignoredButton, 'closest').and.callThrough();
- });
-
- it('does not select element', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.ignoredButton.closest.calls.count()).toBe(1);
- expect(this.ignoredButton.closest).toHaveBeenCalledWith('.droplab-item-ignore');
- expect(this.dropdown.addSelectedClass).not.toHaveBeenCalled();
- });
- });
-
- describe('if no selected element exists', function() {
- beforeEach(function() {
- this.event.preventDefault.calls.reset();
- this.dummyListItem = null;
- });
-
- it('should return before .preventDefault is called', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.event.preventDefault).not.toHaveBeenCalled();
- expect(this.dropdown.addSelectedClass).not.toHaveBeenCalled();
- });
- });
-
- describe('if hideOnClick is false', () => {
- beforeEach(function() {
- this.dropdown.hideOnClick = false;
- this.dropdown.hide.calls.reset();
- });
-
- it('should not call .hide', function() {
- DropDown.prototype.clickEvent.call(this.dropdown, this.event);
-
- expect(this.dropdown.hide).not.toHaveBeenCalled();
- });
- });
- });
-
- describe('addSelectedClass', function() {
- beforeEach(function() {
- this.items = Array(4).forEach((item, i) => {
- this.items[i] = { classList: { add: () => {} } };
- spyOn(this.items[i].classList, 'add');
- });
- this.selected = { classList: { add: () => {} } };
- this.dropdown = { removeSelectedClasses: () => {} };
-
- spyOn(this.dropdown, 'removeSelectedClasses');
- spyOn(this.selected.classList, 'add');
-
- DropDown.prototype.addSelectedClass.call(this.dropdown, this.selected);
- });
-
- it('should call .removeSelectedClasses', function() {
- expect(this.dropdown.removeSelectedClasses).toHaveBeenCalled();
- });
-
- it('should call .classList.add', function() {
- expect(this.selected.classList.add).toHaveBeenCalledWith(SELECTED_CLASS);
- });
- });
-
- describe('removeSelectedClasses', function() {
- beforeEach(function() {
- this.items = Array(4);
- this.items.forEach((item, i) => {
- this.items[i] = { classList: { add: () => {} } };
- spyOn(this.items[i].classList, 'add');
- });
- this.dropdown = { items: this.items };
-
- DropDown.prototype.removeSelectedClasses.call(this.dropdown);
- });
-
- it('should call .classList.remove for all items', function() {
- this.items.forEach((item, i) => {
- expect(this.items[i].classList.add).toHaveBeenCalledWith(SELECTED_CLASS);
- });
- });
-
- describe('if .items is not set', function() {
- beforeEach(function() {
- this.dropdown = { getItems: () => {} };
-
- spyOn(this.dropdown, 'getItems').and.returnValue([]);
-
- DropDown.prototype.removeSelectedClasses.call(this.dropdown);
- });
-
- it('should call .getItems', function() {
- expect(this.dropdown.getItems).toHaveBeenCalled();
- });
- });
- });
-
- describe('addEvents', function() {
- beforeEach(function() {
- this.list = {
- addEventListener: () => {},
- querySelectorAll: () => [],
- };
- this.dropdown = {
- list: this.list,
- clickEvent: () => {},
- closeDropdown: () => {},
- eventWrapper: {},
- };
- });
-
- it('should call .addEventListener', function() {
- spyOn(this.list, 'addEventListener');
-
- DropDown.prototype.addEvents.call(this.dropdown);
-
- expect(this.list.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function));
- expect(this.list.addEventListener).toHaveBeenCalledWith('keyup', jasmine.any(Function));
- });
- });
-
- describe('setData', function() {
- beforeEach(function() {
- this.dropdown = { render: () => {} };
- this.data = ['data'];
-
- spyOn(this.dropdown, 'render');
-
- DropDown.prototype.setData.call(this.dropdown, this.data);
- });
-
- it('should set .data', function() {
- expect(this.dropdown.data).toBe(this.data);
- });
-
- it('should call .render with the .data', function() {
- expect(this.dropdown.render).toHaveBeenCalledWith(this.data);
- });
- });
-
- describe('addData', function() {
- beforeEach(function() {
- this.dropdown = { render: () => {}, data: ['data1'] };
- this.data = ['data2'];
-
- spyOn(this.dropdown, 'render');
- spyOn(Array.prototype, 'concat').and.callThrough();
-
- DropDown.prototype.addData.call(this.dropdown, this.data);
- });
-
- it('should call .concat with data', function() {
- expect(Array.prototype.concat).toHaveBeenCalledWith(this.data);
- });
-
- it('should set .data with concatination', function() {
- expect(this.dropdown.data).toEqual(['data1', 'data2']);
- });
-
- it('should call .render with the .data', function() {
- expect(this.dropdown.render).toHaveBeenCalledWith(['data1', 'data2']);
- });
-
- describe('if .data is undefined', function() {
- beforeEach(function() {
- this.dropdown = { render: () => {}, data: undefined };
- this.data = ['data2'];
-
- spyOn(this.dropdown, 'render');
-
- DropDown.prototype.addData.call(this.dropdown, this.data);
- });
-
- it('should set .data with concatination', function() {
- expect(this.dropdown.data).toEqual(['data2']);
- });
- });
- });
-
- describe('render', function() {
- beforeEach(function() {
- this.renderableList = {};
- this.list = {
- querySelector: q => {
- if (q === '.filter-dropdown-loading') {
- return false;
- }
- return this.renderableList;
- },
- dispatchEvent: () => {},
- };
- this.dropdown = { renderChildren: () => {}, list: this.list };
- this.data = [0, 1];
- this.customEvent = {};
-
- spyOn(this.dropdown, 'renderChildren').and.callFake(data => data);
- spyOn(this.list, 'dispatchEvent');
- spyOn(this.data, 'map').and.callThrough();
- spyOn(window, 'CustomEvent').and.returnValue(this.customEvent);
-
- DropDown.prototype.render.call(this.dropdown, this.data);
- });
-
- it('should call .map', function() {
- expect(this.data.map).toHaveBeenCalledWith(jasmine.any(Function));
- });
-
- it('should call .renderChildren for each data item', function() {
- expect(this.dropdown.renderChildren.calls.count()).toBe(this.data.length);
- });
-
- it('sets the renderableList .innerHTML', function() {
- expect(this.renderableList.innerHTML).toBe('01');
- });
-
- it('should call render.dl', function() {
- expect(window.CustomEvent).toHaveBeenCalledWith('render.dl', jasmine.any(Object));
- });
-
- it('should call dispatchEvent with the customEvent', function() {
- expect(this.list.dispatchEvent).toHaveBeenCalledWith(this.customEvent);
- });
-
- describe('if no data argument is passed', function() {
- beforeEach(function() {
- this.data.map.calls.reset();
- this.dropdown.renderChildren.calls.reset();
-
- DropDown.prototype.render.call(this.dropdown, undefined);
- });
-
- it('should not call .map', function() {
- expect(this.data.map).not.toHaveBeenCalled();
- });
-
- it('should not call .renderChildren', function() {
- expect(this.dropdown.renderChildren).not.toHaveBeenCalled();
- });
- });
-
- describe('if no dynamic list is present', function() {
- beforeEach(function() {
- this.list = { querySelector: () => {}, dispatchEvent: () => {} };
- this.dropdown = { renderChildren: () => {}, list: this.list };
- this.data = [0, 1];
-
- spyOn(this.dropdown, 'renderChildren').and.callFake(data => data);
- spyOn(this.list, 'querySelector');
- spyOn(this.data, 'map').and.callThrough();
-
- DropDown.prototype.render.call(this.dropdown, this.data);
- });
-
- it('sets the .list .innerHTML', function() {
- expect(this.list.innerHTML).toBe('01');
- });
- });
- });
-
- describe('renderChildren', function() {
- beforeEach(function() {
- this.templateString = 'templateString';
- this.dropdown = { templateString: this.templateString };
- this.data = { droplab_hidden: true };
- this.html = 'html';
- this.template = { firstChild: { outerHTML: 'outerHTML', style: {} } };
-
- spyOn(utils, 'template').and.returnValue(this.html);
- spyOn(document, 'createElement').and.returnValue(this.template);
- spyOn(DropDown, 'setImagesSrc');
-
- this.renderChildren = DropDown.prototype.renderChildren.call(this.dropdown, this.data);
- });
-
- it('should call utils.t with .templateString and data', function() {
- expect(utils.template).toHaveBeenCalledWith(this.templateString, this.data);
- });
-
- it('should call document.createElement', function() {
- expect(document.createElement).toHaveBeenCalledWith('div');
- });
-
- it('should set the templates .innerHTML to the HTML', function() {
- expect(this.template.innerHTML).toBe(this.html);
- });
-
- it('should call .setImagesSrc with the template', function() {
- expect(DropDown.setImagesSrc).toHaveBeenCalledWith(this.template);
- });
-
- it('should set the template display to none', function() {
- expect(this.template.firstChild.style.display).toBe('none');
- });
-
- it('should return the templates .firstChild.outerHTML', function() {
- expect(this.renderChildren).toBe(this.template.firstChild.outerHTML);
- });
-
- describe('if droplab_hidden is false', function() {
- beforeEach(function() {
- this.data = { droplab_hidden: false };
- this.renderChildren = DropDown.prototype.renderChildren.call(this.dropdown, this.data);
- });
-
- it('should set the template display to block', function() {
- expect(this.template.firstChild.style.display).toBe('block');
- });
- });
- });
-
- describe('setImagesSrc', function() {
- beforeEach(function() {
- this.template = { querySelectorAll: () => {} };
-
- spyOn(this.template, 'querySelectorAll').and.returnValue([]);
-
- DropDown.setImagesSrc(this.template);
- });
-
- it('should call .querySelectorAll', function() {
- expect(this.template.querySelectorAll).toHaveBeenCalledWith('img[data-src]');
- });
- });
-
- describe('show', function() {
- beforeEach(function() {
- this.list = { style: {} };
- this.dropdown = { list: this.list, hidden: true };
-
- DropDown.prototype.show.call(this.dropdown);
- });
-
- it('it should set .list display to block', function() {
- expect(this.list.style.display).toBe('block');
- });
-
- it('it should set .hidden to false', function() {
- expect(this.dropdown.hidden).toBe(false);
- });
-
- describe('if .hidden is false', function() {
- beforeEach(function() {
- this.list = { style: {} };
- this.dropdown = { list: this.list, hidden: false };
-
- this.show = DropDown.prototype.show.call(this.dropdown);
- });
-
- it('should return undefined', function() {
- expect(this.show).toEqual(undefined);
- });
-
- it('should not set .list display to block', function() {
- expect(this.list.style.display).not.toEqual('block');
- });
- });
- });
-
- describe('hide', function() {
- beforeEach(function() {
- this.list = { style: {} };
- this.dropdown = { list: this.list };
-
- DropDown.prototype.hide.call(this.dropdown);
- });
-
- it('it should set .list display to none', function() {
- expect(this.list.style.display).toBe('none');
- });
-
- it('it should set .hidden to true', function() {
- expect(this.dropdown.hidden).toBe(true);
- });
- });
-
- describe('toggle', function() {
- beforeEach(function() {
- this.hidden = true;
- this.dropdown = { hidden: this.hidden, show: () => {}, hide: () => {} };
-
- spyOn(this.dropdown, 'show');
- spyOn(this.dropdown, 'hide');
-
- DropDown.prototype.toggle.call(this.dropdown);
- });
-
- it('should call .show', function() {
- expect(this.dropdown.show).toHaveBeenCalled();
- });
-
- describe('if .hidden is false', function() {
- beforeEach(function() {
- this.hidden = false;
- this.dropdown = { hidden: this.hidden, show: () => {}, hide: () => {} };
-
- spyOn(this.dropdown, 'show');
- spyOn(this.dropdown, 'hide');
-
- DropDown.prototype.toggle.call(this.dropdown);
- });
-
- it('should call .hide', function() {
- expect(this.dropdown.hide).toHaveBeenCalled();
- });
- });
- });
-
- describe('destroy', function() {
- beforeEach(function() {
- this.list = { removeEventListener: () => {} };
- this.eventWrapper = { clickEvent: 'clickEvent' };
- this.dropdown = { list: this.list, hide: () => {}, eventWrapper: this.eventWrapper };
-
- spyOn(this.list, 'removeEventListener');
- spyOn(this.dropdown, 'hide');
-
- DropDown.prototype.destroy.call(this.dropdown);
- });
-
- it('it should call .hide', function() {
- expect(this.dropdown.hide).toHaveBeenCalled();
- });
-
- it('it should call .removeEventListener', function() {
- expect(this.list.removeEventListener).toHaveBeenCalledWith(
- 'click',
- this.eventWrapper.clickEvent,
- );
- });
- });
-});
diff --git a/spec/javascripts/droplab/hook_spec.js b/spec/javascripts/droplab/hook_spec.js
deleted file mode 100644
index 40470436f19..00000000000
--- a/spec/javascripts/droplab/hook_spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import Hook from '~/droplab/hook';
-
-describe('Hook', function() {
- describe('class constructor', function() {
- beforeEach(function() {
- this.trigger = { id: 'id' };
- this.list = {};
- this.plugins = {};
- this.config = {};
- this.dropdown = {};
-
- this.dropdownConstructor = spyOnDependency(Hook, 'DropDown').and.returnValue(this.dropdown);
-
- this.hook = new Hook(this.trigger, this.list, this.plugins, this.config);
- });
-
- it('should set .trigger', function() {
- expect(this.hook.trigger).toBe(this.trigger);
- });
-
- it('should set .list', function() {
- expect(this.hook.list).toBe(this.dropdown);
- });
-
- it('should call DropDown constructor', function() {
- expect(this.dropdownConstructor).toHaveBeenCalledWith(this.list, this.config);
- });
-
- it('should set .type', function() {
- expect(this.hook.type).toBe('Hook');
- });
-
- it('should set .event', function() {
- expect(this.hook.event).toBe('click');
- });
-
- it('should set .plugins', function() {
- expect(this.hook.plugins).toBe(this.plugins);
- });
-
- it('should set .config', function() {
- expect(this.hook.config).toBe(this.config);
- });
-
- it('should set .id', function() {
- expect(this.hook.id).toBe(this.trigger.id);
- });
-
- describe('if config argument is undefined', function() {
- beforeEach(function() {
- this.config = undefined;
-
- this.hook = new Hook(this.trigger, this.list, this.plugins, this.config);
- });
-
- it('should set .config to an empty object', function() {
- expect(this.hook.config).toEqual({});
- });
- });
-
- describe('if plugins argument is undefined', function() {
- beforeEach(function() {
- this.plugins = undefined;
-
- this.hook = new Hook(this.trigger, this.list, this.plugins, this.config);
- });
-
- it('should set .plugins to an empty array', function() {
- expect(this.hook.plugins).toEqual([]);
- });
- });
- });
-});
diff --git a/spec/javascripts/droplab/plugins/input_setter_spec.js b/spec/javascripts/droplab/plugins/input_setter_spec.js
deleted file mode 100644
index 711e0486bff..00000000000
--- a/spec/javascripts/droplab/plugins/input_setter_spec.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import InputSetter from '~/droplab/plugins/input_setter';
-
-describe('InputSetter', function() {
- describe('init', function() {
- beforeEach(function() {
- this.config = { InputSetter: {} };
- this.hook = { config: this.config };
- this.inputSetter = jasmine.createSpyObj('inputSetter', ['addEvents']);
-
- InputSetter.init.call(this.inputSetter, this.hook);
- });
-
- it('should set .hook', function() {
- expect(this.inputSetter.hook).toBe(this.hook);
- });
-
- it('should set .config', function() {
- expect(this.inputSetter.config).toBe(this.config.InputSetter);
- });
-
- it('should set .eventWrapper', function() {
- expect(this.inputSetter.eventWrapper).toEqual({});
- });
-
- it('should call .addEvents', function() {
- expect(this.inputSetter.addEvents).toHaveBeenCalled();
- });
-
- describe('if config.InputSetter is not set', function() {
- beforeEach(function() {
- this.config = { InputSetter: undefined };
- this.hook = { config: this.config };
-
- InputSetter.init.call(this.inputSetter, this.hook);
- });
-
- it('should set .config to an empty object', function() {
- expect(this.inputSetter.config).toEqual({});
- });
-
- it('should set hook.config to an empty object', function() {
- expect(this.hook.config.InputSetter).toEqual({});
- });
- });
- });
-
- describe('addEvents', function() {
- beforeEach(function() {
- this.hook = { list: { list: jasmine.createSpyObj('list', ['addEventListener']) } };
- this.inputSetter = { eventWrapper: {}, hook: this.hook, setInputs: () => {} };
-
- InputSetter.addEvents.call(this.inputSetter);
- });
-
- it('should set .eventWrapper.setInputs', function() {
- expect(this.inputSetter.eventWrapper.setInputs).toEqual(jasmine.any(Function));
- });
-
- it('should call .addEventListener', function() {
- expect(this.hook.list.list.addEventListener).toHaveBeenCalledWith(
- 'click.dl',
- this.inputSetter.eventWrapper.setInputs,
- );
- });
- });
-
- describe('removeEvents', function() {
- beforeEach(function() {
- this.hook = { list: { list: jasmine.createSpyObj('list', ['removeEventListener']) } };
- this.eventWrapper = jasmine.createSpyObj('eventWrapper', ['setInputs']);
- this.inputSetter = { eventWrapper: this.eventWrapper, hook: this.hook };
-
- InputSetter.removeEvents.call(this.inputSetter);
- });
-
- it('should call .removeEventListener', function() {
- expect(this.hook.list.list.removeEventListener).toHaveBeenCalledWith(
- 'click.dl',
- this.eventWrapper.setInputs,
- );
- });
- });
-
- describe('setInputs', function() {
- beforeEach(function() {
- this.event = { detail: { selected: {} } };
- this.config = [0, 1];
- this.inputSetter = { config: this.config, setInput: () => {} };
-
- spyOn(this.inputSetter, 'setInput');
-
- InputSetter.setInputs.call(this.inputSetter, this.event);
- });
-
- it('should call .setInput for each config element', function() {
- const allArgs = this.inputSetter.setInput.calls.allArgs();
-
- expect(allArgs.length).toEqual(2);
-
- allArgs.forEach((args, i) => {
- expect(args[0]).toBe(this.config[i]);
- expect(args[1]).toBe(this.event.detail.selected);
- });
- });
-
- describe('if config isnt an array', function() {
- beforeEach(function() {
- this.inputSetter = { config: {}, setInput: () => {} };
-
- InputSetter.setInputs.call(this.inputSetter, this.event);
- });
-
- it('should set .config to an array with .config as the first element', function() {
- expect(this.inputSetter.config).toEqual([{}]);
- });
- });
- });
-
- describe('setInput', function() {
- beforeEach(function() {
- this.selectedItem = { getAttribute: () => {} };
- this.input = { value: 'oldValue', tagName: 'INPUT', hasAttribute: () => {} };
- this.config = { valueAttribute: {}, input: this.input };
- this.inputSetter = { hook: { trigger: {} } };
- this.newValue = 'newValue';
-
- spyOn(this.selectedItem, 'getAttribute').and.returnValue(this.newValue);
- spyOn(this.input, 'hasAttribute').and.returnValue(false);
-
- InputSetter.setInput.call(this.inputSetter, this.config, this.selectedItem);
- });
-
- it('should call .getAttribute', function() {
- expect(this.selectedItem.getAttribute).toHaveBeenCalledWith(this.config.valueAttribute);
- });
-
- it('should call .hasAttribute', function() {
- expect(this.input.hasAttribute).toHaveBeenCalledWith(undefined);
- });
-
- it('should set the value of the input', function() {
- expect(this.input.value).toBe(this.newValue);
- });
-
- describe('if no config.input is provided', function() {
- beforeEach(function() {
- this.config = { valueAttribute: {} };
- this.trigger = { value: 'oldValue', tagName: 'INPUT', hasAttribute: () => {} };
- this.inputSetter = { hook: { trigger: this.trigger } };
-
- InputSetter.setInput.call(this.inputSetter, this.config, this.selectedItem);
- });
-
- it('should set the value of the hook.trigger', function() {
- expect(this.trigger.value).toBe(this.newValue);
- });
- });
-
- describe('if the input tag is not INPUT', function() {
- beforeEach(function() {
- this.input = { textContent: 'oldValue', tagName: 'SPAN', hasAttribute: () => {} };
- this.config = { valueAttribute: {}, input: this.input };
-
- InputSetter.setInput.call(this.inputSetter, this.config, this.selectedItem);
- });
-
- it('should set the textContent of the input', function() {
- expect(this.input.textContent).toBe(this.newValue);
- });
- });
-
- describe('if there is an inputAttribute', function() {
- beforeEach(function() {
- this.selectedItem = { getAttribute: () => {} };
- this.input = { id: 'oldValue', hasAttribute: () => {}, setAttribute: () => {} };
- this.inputSetter = { hook: { trigger: {} } };
- this.newValue = 'newValue';
- this.inputAttribute = 'id';
- this.config = {
- valueAttribute: {},
- input: this.input,
- inputAttribute: this.inputAttribute,
- };
-
- spyOn(this.selectedItem, 'getAttribute').and.returnValue(this.newValue);
- spyOn(this.input, 'hasAttribute').and.returnValue(true);
- spyOn(this.input, 'setAttribute');
-
- InputSetter.setInput.call(this.inputSetter, this.config, this.selectedItem);
- });
-
- it('should call setAttribute', function() {
- expect(this.input.setAttribute).toHaveBeenCalledWith(this.inputAttribute, this.newValue);
- });
-
- it('should not set the value or textContent of the input', function() {
- expect(this.input.value).not.toBe('newValue');
- expect(this.input.textContent).not.toBe('newValue');
- });
- });
- });
-
- describe('destroy', function() {
- beforeEach(function() {
- this.inputSetter = jasmine.createSpyObj('inputSetter', ['removeEvents']);
-
- InputSetter.destroy.call(this.inputSetter);
- });
-
- it('should call .removeEvents', function() {
- expect(this.inputSetter.removeEvents).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/javascripts/dropzone_input_spec.js b/spec/javascripts/dropzone_input_spec.js
deleted file mode 100644
index 6f6f20ccca2..00000000000
--- a/spec/javascripts/dropzone_input_spec.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import $ from 'jquery';
-import { TEST_HOST } from 'spec/test_constants';
-import dropzoneInput from '~/dropzone_input';
-import PasteMarkdownTable from '~/behaviors/markdown/paste_markdown_table';
-
-const TEST_FILE = new File([], 'somefile.jpg');
-TEST_FILE.upload = {};
-
-const TEST_UPLOAD_PATH = `${TEST_HOST}/upload/file`;
-const TEST_ERROR_MESSAGE = 'A big error occurred!';
-const TEMPLATE = `<form class="gfm-form" data-uploads-path="${TEST_UPLOAD_PATH}">
- <textarea class="js-gfm-input"></textarea>
- <div class="uploading-error-message"></div>
-</form>`;
-
-describe('dropzone_input', () => {
- it('returns null when failed to initialize', () => {
- const dropzone = dropzoneInput($('<form class="gfm-form"></form>'));
-
- expect(dropzone).toBeNull();
- });
-
- it('returns valid dropzone when successfully initialize', () => {
- const dropzone = dropzoneInput($(TEMPLATE));
-
- expect(dropzone.version).toBeTruthy();
- });
-
- describe('handlePaste', () => {
- beforeEach(() => {
- loadFixtures('issues/new-issue.html');
-
- const form = $('#new_issue');
- form.data('uploads-path', TEST_UPLOAD_PATH);
- dropzoneInput(form);
- });
-
- it('pastes Markdown tables', () => {
- const event = $.Event('paste');
- const origEvent = new Event('paste');
- const pasteData = new DataTransfer();
- pasteData.setData('text/plain', 'Hello World');
- pasteData.setData('text/html', '<table><tr><td>Hello World</td></tr></table>');
- origEvent.clipboardData = pasteData;
- event.originalEvent = origEvent;
-
- spyOn(PasteMarkdownTable.prototype, 'isTable').and.callThrough();
- spyOn(PasteMarkdownTable.prototype, 'convertToTableMarkdown').and.callThrough();
-
- $('.js-gfm-input').trigger(event);
-
- expect(PasteMarkdownTable.prototype.isTable).toHaveBeenCalled();
- expect(PasteMarkdownTable.prototype.convertToTableMarkdown).toHaveBeenCalled();
- });
- });
-
- describe('shows error message', () => {
- let form;
- let dropzone;
- let xhr;
- let oldXMLHttpRequest;
-
- beforeEach(() => {
- form = $(TEMPLATE);
-
- dropzone = dropzoneInput(form);
-
- xhr = jasmine.createSpyObj(Object.keys(XMLHttpRequest.prototype));
- oldXMLHttpRequest = window.XMLHttpRequest;
- window.XMLHttpRequest = () => xhr;
- });
-
- afterEach(() => {
- window.XMLHttpRequest = oldXMLHttpRequest;
- });
-
- it('when AJAX fails with json', () => {
- xhr = {
- ...xhr,
- statusCode: 400,
- readyState: 4,
- responseText: JSON.stringify({ message: TEST_ERROR_MESSAGE }),
- getResponseHeader: () => 'application/json',
- };
-
- dropzone.processFile(TEST_FILE);
-
- xhr.onload();
-
- expect(form.find('.uploading-error-message').text()).toEqual(TEST_ERROR_MESSAGE);
- });
-
- it('when AJAX fails with text', () => {
- xhr = {
- ...xhr,
- statusCode: 400,
- readyState: 4,
- responseText: TEST_ERROR_MESSAGE,
- getResponseHeader: () => 'text/plain',
- };
-
- dropzone.processFile(TEST_FILE);
-
- xhr.onload();
-
- expect(form.find('.uploading-error-message').text()).toEqual(TEST_ERROR_MESSAGE);
- });
- });
-});
diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js
deleted file mode 100644
index 853f6b3b7b8..00000000000
--- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import $ from 'jquery';
-import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager';
-
-describe('Filtered Search Dropdown Manager', () => {
- beforeEach(() => {
- spyOn($, 'ajax');
- });
-
- describe('addWordToInput', () => {
- function getInputValue() {
- return document.querySelector('.filtered-search').value;
- }
-
- function setInputValue(value) {
- document.querySelector('.filtered-search').value = value;
- }
-
- beforeEach(() => {
- setFixtures(`
- <ul class="tokens-container">
- <li class="input-token">
- <input class="filtered-search">
- </li>
- </ul>
- `);
- });
-
- describe('input has no existing value', () => {
- it('should add just tokenName', () => {
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'milestone' });
-
- const token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('milestone');
- expect(getInputValue()).toBe('');
- });
-
- it('should add tokenName, tokenOperator, and tokenValue', () => {
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label' });
-
- let token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('label');
- expect(getInputValue()).toBe('');
-
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label', tokenOperator: '=' });
-
- token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('label');
- expect(token.querySelector('.operator').innerText).toBe('=');
- expect(getInputValue()).toBe('');
-
- FilteredSearchDropdownManager.addWordToInput({
- tokenName: 'label',
- tokenOperator: '=',
- tokenValue: 'none',
- });
- // We have to get that reference again
- // Because FilteredSearchDropdownManager deletes the previous token
- token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('label');
- expect(token.querySelector('.operator').innerText).toBe('=');
- expect(token.querySelector('.value').innerText).toBe('none');
- expect(getInputValue()).toBe('');
- });
- });
-
- describe('input has existing value', () => {
- it('should be able to just add tokenName', () => {
- setInputValue('a');
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author' });
-
- const token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('author');
- expect(getInputValue()).toBe('');
- });
-
- it('should replace tokenValue', () => {
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author' });
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author', tokenOperator: '=' });
-
- setInputValue('roo');
- FilteredSearchDropdownManager.addWordToInput({
- tokenName: null,
- tokenOperator: '=',
- tokenValue: '@root',
- });
-
- const token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('author');
- expect(token.querySelector('.operator').innerText).toBe('=');
- expect(token.querySelector('.value').innerText).toBe('@root');
- expect(getInputValue()).toBe('');
- });
-
- it('should add tokenValues containing spaces', () => {
- FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label' });
-
- setInputValue('"test ');
- FilteredSearchDropdownManager.addWordToInput({
- tokenName: 'label',
- tokenOperator: '=',
- tokenValue: '~\'"test me"\'',
- });
-
- const token = document.querySelector('.tokens-container .js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toBe('label');
- expect(token.querySelector('.operator').innerText).toBe('=');
- expect(token.querySelector('.value').innerText).toBe('~\'"test me"\'');
- expect(getInputValue()).toBe('');
- });
- });
- });
-});
diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
deleted file mode 100644
index fda078bd41c..00000000000
--- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
+++ /dev/null
@@ -1,722 +0,0 @@
-import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
-import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper';
-
-describe('Filtered Search Visual Tokens', () => {
- const subject = FilteredSearchVisualTokens;
-
- const findElements = tokenElement => {
- const tokenNameElement = tokenElement.querySelector('.name');
- const tokenOperatorElement = tokenElement.querySelector('.operator');
- const tokenValueContainer = tokenElement.querySelector('.value-container');
- const tokenValueElement = tokenValueContainer.querySelector('.value');
- return { tokenNameElement, tokenOperatorElement, tokenValueContainer, tokenValueElement };
- };
-
- let tokensContainer;
- let authorToken;
- let bugLabelToken;
-
- beforeEach(() => {
- setFixtures(`
- <ul class="tokens-container">
- ${FilteredSearchSpecHelper.createInputHTML()}
- </ul>
- `);
- tokensContainer = document.querySelector('.tokens-container');
-
- authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user');
- bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '=', '~bug');
- });
-
- describe('getLastVisualTokenBeforeInput', () => {
- it('returns when there are no visual tokens', () => {
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
-
- expect(lastVisualToken).toEqual(null);
- expect(isLastVisualTokenValid).toEqual(true);
- });
-
- describe('input is the last item in tokensContainer', () => {
- it('returns when there is one visual token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- bugLabelToken.outerHTML,
- );
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
-
- expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
- expect(isLastVisualTokenValid).toEqual(true);
- });
-
- it('returns when there is an incomplete visual token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('Author'),
- );
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
-
- expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
- expect(isLastVisualTokenValid).toEqual(false);
- });
-
- it('returns when there are multiple visual tokens', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${bugLabelToken.outerHTML}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
- `);
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
- const items = document.querySelectorAll('.tokens-container .js-visual-token');
-
- expect(lastVisualToken.isEqualNode(items[items.length - 1])).toEqual(true);
- expect(isLastVisualTokenValid).toEqual(true);
- });
-
- it('returns when there are multiple visual tokens and an incomplete visual token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${bugLabelToken.outerHTML}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- ${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('assignee')}
- `);
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
- const items = document.querySelectorAll('.tokens-container .js-visual-token');
-
- expect(lastVisualToken.isEqualNode(items[items.length - 1])).toEqual(true);
- expect(isLastVisualTokenValid).toEqual(false);
- });
- });
-
- describe('input is a middle item in tokensContainer', () => {
- it('returns last token before input', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${bugLabelToken.outerHTML}
- ${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
- `);
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
-
- expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
- expect(isLastVisualTokenValid).toEqual(true);
- });
-
- it('returns last partial token before input', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label')}
- ${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
- `);
-
- const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
-
- expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
- expect(isLastVisualTokenValid).toEqual(false);
- });
- });
- });
-
- describe('getEndpointWithQueryParams', () => {
- it('returns `endpoint` string as is when second param `endpointQueryParams` is undefined, null or empty string', () => {
- const endpoint = 'foo/bar/-/labels.json';
-
- expect(subject.getEndpointWithQueryParams(endpoint)).toBe(endpoint);
- expect(subject.getEndpointWithQueryParams(endpoint, null)).toBe(endpoint);
- expect(subject.getEndpointWithQueryParams(endpoint, '')).toBe(endpoint);
- });
-
- it('returns `endpoint` string with values of `endpointQueryParams`', () => {
- const endpoint = 'foo/bar/-/labels.json';
- const singleQueryParams = '{"foo":"true"}';
- const multipleQueryParams = '{"foo":"true","bar":"true"}';
-
- expect(subject.getEndpointWithQueryParams(endpoint, singleQueryParams)).toBe(
- `${endpoint}?foo=true`,
- );
-
- expect(subject.getEndpointWithQueryParams(endpoint, multipleQueryParams)).toBe(
- `${endpoint}?foo=true&bar=true`,
- );
- });
- });
-
- describe('unselectTokens', () => {
- it('does nothing when there are no tokens', () => {
- const beforeHTML = tokensContainer.innerHTML;
- subject.unselectTokens();
-
- expect(tokensContainer.innerHTML).toEqual(beforeHTML);
- });
-
- it('removes the selected class from buttons', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@author')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', '%123', true)}
- `);
-
- const selected = tokensContainer.querySelector('.js-visual-token .selected');
-
- expect(selected.classList.contains('selected')).toEqual(true);
-
- subject.unselectTokens();
-
- expect(selected.classList.contains('selected')).toEqual(false);
- });
- });
-
- describe('selectToken', () => {
- beforeEach(() => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${bugLabelToken.outerHTML}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~awesome')}
- `);
- });
-
- it('removes the selected class if it has selected class', () => {
- const firstTokenButton = tokensContainer.querySelector('.js-visual-token .selectable');
- firstTokenButton.classList.add('selected');
-
- subject.selectToken(firstTokenButton);
-
- expect(firstTokenButton.classList.contains('selected')).toEqual(false);
- });
-
- describe('has no selected class', () => {
- it('adds selected class', () => {
- const firstTokenButton = tokensContainer.querySelector('.js-visual-token .selectable');
-
- subject.selectToken(firstTokenButton);
-
- expect(firstTokenButton.classList.contains('selected')).toEqual(true);
- });
-
- it('removes selected class from other tokens', () => {
- const tokenButtons = tokensContainer.querySelectorAll('.js-visual-token .selectable');
- tokenButtons[1].classList.add('selected');
-
- subject.selectToken(tokenButtons[0]);
-
- expect(tokenButtons[0].classList.contains('selected')).toEqual(true);
- expect(tokenButtons[1].classList.contains('selected')).toEqual(false);
- });
- });
- });
-
- describe('removeSelectedToken', () => {
- it('does not remove when there are no selected tokens', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none'),
- );
-
- expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
-
- subject.removeSelectedToken();
-
- expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
- });
-
- it('removes selected token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
- );
-
- expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
-
- subject.removeSelectedToken();
-
- expect(tokensContainer.querySelector('.js-visual-token .selectable')).toEqual(null);
- });
- });
-
- describe('createVisualTokenElementHTML', () => {
- let tokenElement;
-
- beforeEach(() => {
- setFixtures(`
- <div class="test-area">
- ${subject.createVisualTokenElementHTML('custom-token')}
- </div>
- `);
-
- tokenElement = document.querySelector('.test-area').firstElementChild;
- });
-
- it('should add class name to token element', () => {
- expect(document.querySelector('.test-area .custom-token')).toBeDefined();
- });
-
- it('contains name div', () => {
- expect(tokenElement.querySelector('.name')).toEqual(jasmine.anything());
- });
-
- it('contains value container div', () => {
- expect(tokenElement.querySelector('.value-container')).toEqual(jasmine.anything());
- });
-
- it('contains value div', () => {
- expect(tokenElement.querySelector('.value-container .value')).toEqual(jasmine.anything());
- });
-
- it('contains selectable class', () => {
- expect(tokenElement.classList.contains('selectable')).toEqual(true);
- });
-
- it('contains button role', () => {
- expect(tokenElement.getAttribute('role')).toEqual('button');
- });
-
- describe('remove token', () => {
- it('contains remove-token button', () => {
- expect(tokenElement.querySelector('.value-container .remove-token')).toEqual(
- jasmine.anything(),
- );
- });
-
- it('contains fa-close icon', () => {
- expect(tokenElement.querySelector('.remove-token .fa-close')).toEqual(jasmine.anything());
- });
- });
- });
-
- describe('addVisualTokenElement', () => {
- it('renders search visual tokens', () => {
- subject.addVisualTokenElement({
- name: 'search term',
- operator: '=',
- value: null,
- options: { isSearchTerm: true },
- });
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('filtered-search-term')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('search term');
- expect(token.querySelector('.operator').innerText).toEqual('=');
- expect(token.querySelector('.value')).toEqual(null);
- });
-
- it('renders filter visual token name', () => {
- subject.addVisualTokenElement({ name: 'milestone' });
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('search-token-milestone')).toEqual(true);
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('milestone');
- expect(token.querySelector('.value')).toEqual(null);
- });
-
- it('renders filter visual token name, operator, and value', () => {
- subject.addVisualTokenElement({ name: 'label', operator: '!=', value: 'Frontend' });
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('search-token-label')).toEqual(true);
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('label');
- expect(token.querySelector('.operator').innerText).toEqual('!=');
- expect(token.querySelector('.value').innerText).toEqual('Frontend');
- });
-
- it('inserts visual token before input', () => {
- tokensContainer.appendChild(
- FilteredSearchSpecHelper.createFilterVisualToken('assignee', '=', '@root'),
- );
-
- subject.addVisualTokenElement({ name: 'label', operator: '!=', value: 'Frontend' });
- const tokens = tokensContainer.querySelectorAll('.js-visual-token');
- const labelToken = tokens[0];
- const assigneeToken = tokens[1];
-
- expect(labelToken.classList.contains('search-token-label')).toEqual(true);
- expect(labelToken.classList.contains('filtered-search-token')).toEqual(true);
- expect(labelToken.querySelector('.name').innerText).toEqual('label');
- expect(labelToken.querySelector('.value').innerText).toEqual('Frontend');
- expect(labelToken.querySelector('.operator').innerText).toEqual('!=');
-
- expect(assigneeToken.classList.contains('search-token-assignee')).toEqual(true);
- expect(assigneeToken.classList.contains('filtered-search-token')).toEqual(true);
- expect(assigneeToken.querySelector('.name').innerText).toEqual('assignee');
- expect(assigneeToken.querySelector('.value').innerText).toEqual('@root');
- expect(assigneeToken.querySelector('.operator').innerText).toEqual('=');
- });
- });
-
- describe('addValueToPreviousVisualTokenElement', () => {
- it('does not add when previous visual token element has no value', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root'),
- );
-
- const original = tokensContainer.innerHTML;
- subject.addValueToPreviousVisualTokenElement('value');
-
- expect(original).toEqual(tokensContainer.innerHTML);
- });
-
- it('does not add when previous visual token element is a search', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- `);
-
- const original = tokensContainer.innerHTML;
- subject.addValueToPreviousVisualTokenElement('value');
-
- expect(original).toEqual(tokensContainer.innerHTML);
- });
-
- it('adds value to previous visual filter token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label', '='),
- );
-
- const original = tokensContainer.innerHTML;
- subject.addValueToPreviousVisualTokenElement('value');
- const updatedToken = tokensContainer.querySelector('.js-visual-token');
-
- expect(updatedToken.querySelector('.name').innerText).toEqual('label');
- expect(updatedToken.querySelector('.value').innerText).toEqual('value');
- expect(original).not.toEqual(tokensContainer.innerHTML);
- });
- });
-
- describe('addFilterVisualToken', () => {
- it('creates visual token with just tokenName', () => {
- subject.addFilterVisualToken('milestone');
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('milestone');
- expect(token.querySelector('.operator')).toEqual(null);
- expect(token.querySelector('.value')).toEqual(null);
- });
-
- it('creates visual token with just tokenValue', () => {
- subject.addFilterVisualToken('milestone', '=');
- subject.addFilterVisualToken('%8.17');
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('milestone');
- expect(token.querySelector('.operator').innerText).toEqual('=');
- expect(token.querySelector('.value').innerText).toEqual('%8.17');
- });
-
- it('creates full visual token', () => {
- subject.addFilterVisualToken('assignee', '=', '@john');
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('filtered-search-token')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('assignee');
- expect(token.querySelector('.operator').innerText).toEqual('=');
- expect(token.querySelector('.value').innerText).toEqual('@john');
- });
- });
-
- describe('addSearchVisualToken', () => {
- it('creates search visual token', () => {
- subject.addSearchVisualToken('search term');
- const token = tokensContainer.querySelector('.js-visual-token');
-
- expect(token.classList.contains('filtered-search-term')).toEqual(true);
- expect(token.querySelector('.name').innerText).toEqual('search term');
- expect(token.querySelector('.value')).toEqual(null);
- });
-
- it('appends to previous search visual token if previous token was a search token', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- `);
-
- subject.addSearchVisualToken('append this');
- const token = tokensContainer.querySelector('.filtered-search-term');
-
- expect(token.querySelector('.name').innerText).toEqual('search term append this');
- expect(token.querySelector('.value')).toEqual(null);
- });
- });
-
- describe('getLastTokenPartial', () => {
- it('should get last token value', () => {
- const value = '~bug';
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- bugLabelToken.outerHTML,
- );
-
- expect(subject.getLastTokenPartial()).toEqual(value);
- });
-
- it('should get last token original value if available', () => {
- const originalValue = '@user';
- const valueContainer = authorToken.querySelector('.value-container');
- valueContainer.dataset.originalValue = originalValue;
- const avatar = document.createElement('img');
- const valueElement = valueContainer.querySelector('.value');
- valueElement.insertAdjacentElement('afterbegin', avatar);
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- authorToken.outerHTML,
- );
-
- const lastTokenValue = subject.getLastTokenPartial();
-
- expect(lastTokenValue).toEqual(originalValue);
- });
-
- it('should get last token name if there is no value', () => {
- const name = 'assignee';
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameFilterVisualTokenHTML(name),
- );
-
- expect(subject.getLastTokenPartial()).toEqual(name);
- });
-
- it('should return empty when there are no tokens', () => {
- expect(subject.getLastTokenPartial()).toEqual('');
- });
- });
-
- describe('removeLastTokenPartial', () => {
- it('should remove the last token value if it exists', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML(
- 'label',
- '=',
- '~"Community Contribution"',
- ),
- );
-
- expect(tokensContainer.querySelector('.js-visual-token .value')).not.toEqual(null);
-
- subject.removeLastTokenPartial();
-
- expect(tokensContainer.querySelector('.js-visual-token .value')).toEqual(null);
- });
-
- it('should remove the last token name if there is no value', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('milestone'),
- );
-
- expect(tokensContainer.querySelector('.js-visual-token .name')).not.toEqual(null);
-
- subject.removeLastTokenPartial();
-
- expect(tokensContainer.querySelector('.js-visual-token .name')).toEqual(null);
- });
-
- it('should not remove anything when there are no tokens', () => {
- const html = tokensContainer.innerHTML;
- subject.removeLastTokenPartial();
-
- expect(tokensContainer.innerHTML).toEqual(html);
- });
- });
-
- describe('tokenizeInput', () => {
- it('does not do anything if there is no input', () => {
- const original = tokensContainer.innerHTML;
- subject.tokenizeInput();
-
- expect(tokensContainer.innerHTML).toEqual(original);
- });
-
- it('adds search visual token if previous visual token is valid', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('assignee', '=', 'none'),
- );
-
- const input = document.querySelector('.filtered-search');
- input.value = 'some value';
- subject.tokenizeInput();
-
- const newToken = tokensContainer.querySelector('.filtered-search-term');
-
- expect(input.value).toEqual('');
- expect(newToken.querySelector('.name').innerText).toEqual('some value');
- expect(newToken.querySelector('.value')).toEqual(null);
- });
-
- it('adds value to previous visual token element if previous visual token is invalid', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('assignee', '='),
- );
-
- const input = document.querySelector('.filtered-search');
- input.value = '@john';
- subject.tokenizeInput();
-
- const updatedToken = tokensContainer.querySelector('.filtered-search-token');
-
- expect(input.value).toEqual('');
- expect(updatedToken.querySelector('.name').innerText).toEqual('assignee');
- expect(updatedToken.querySelector('.operator').innerText).toEqual('=');
- expect(updatedToken.querySelector('.value').innerText).toEqual('@john');
- });
- });
-
- describe('editToken', () => {
- let input;
- let token;
-
- beforeEach(() => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'upcoming')}
- `);
-
- input = document.querySelector('.filtered-search');
- token = document.querySelector('.js-visual-token');
- });
-
- it("tokenize's existing input", () => {
- input.value = 'some text';
- spyOn(subject, 'tokenizeInput').and.callThrough();
-
- subject.editToken(token);
-
- expect(subject.tokenizeInput).toHaveBeenCalled();
- expect(input.value).not.toEqual('some text');
- });
-
- it('moves input to the token position', () => {
- expect(tokensContainer.children[3].querySelector('.filtered-search')).not.toEqual(null);
-
- subject.editToken(token);
-
- expect(tokensContainer.children[1].querySelector('.filtered-search')).not.toEqual(null);
- expect(tokensContainer.children[3].querySelector('.filtered-search')).toEqual(null);
- });
-
- it('input contains the visual token value', () => {
- subject.editToken(token);
-
- expect(input.value).toEqual('none');
- });
-
- it('input contains the original value if present', () => {
- const originalValue = '@user';
- const valueContainer = token.querySelector('.value-container');
- valueContainer.dataset.originalValue = originalValue;
-
- subject.editToken(token);
-
- expect(input.value).toEqual(originalValue);
- });
-
- describe('selected token is a search term token', () => {
- beforeEach(() => {
- token = document.querySelector('.filtered-search-term');
- });
-
- it('token is removed', () => {
- expect(tokensContainer.querySelector('.filtered-search-term')).not.toEqual(null);
-
- subject.editToken(token);
-
- expect(tokensContainer.querySelector('.filtered-search-term')).toEqual(null);
- });
-
- it('input has the same value as removed token', () => {
- expect(input.value).toEqual('');
-
- subject.editToken(token);
-
- expect(input.value).toEqual('search');
- });
- });
- });
-
- describe('moveInputTotheRight', () => {
- it('does nothing if the input is already the right most element', () => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none'),
- );
-
- spyOn(subject, 'tokenizeInput').and.callFake(() => {});
- spyOn(subject, 'getLastVisualTokenBeforeInput').and.callThrough();
-
- subject.moveInputToTheRight();
-
- expect(subject.tokenizeInput).toHaveBeenCalled();
- expect(subject.getLastVisualTokenBeforeInput).not.toHaveBeenCalled();
- });
-
- it("tokenize's input", () => {
- tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label', '=')}
- ${FilteredSearchSpecHelper.createInputHTML()}
- ${bugLabelToken.outerHTML}
- `;
-
- tokensContainer.querySelector('.filtered-search').value = 'none';
-
- subject.moveInputToTheRight();
- const value = tokensContainer.querySelector('.js-visual-token .value');
-
- expect(value.innerText).toEqual('none');
- });
-
- it('converts input into search term token if last token is valid', () => {
- tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
- ${FilteredSearchSpecHelper.createInputHTML()}
- ${bugLabelToken.outerHTML}
- `;
-
- document.querySelector('.filtered-search').value = 'test';
-
- subject.moveInputToTheRight();
- const searchValue = tokensContainer.querySelector('.filtered-search-term .name');
-
- expect(searchValue.innerText).toEqual('test');
- });
-
- it('moves the input to the right most element', () => {
- tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
- ${FilteredSearchSpecHelper.createInputHTML()}
- ${bugLabelToken.outerHTML}
- `;
-
- subject.moveInputToTheRight();
-
- expect(tokensContainer.children[2].querySelector('.filtered-search')).not.toEqual(null);
- });
-
- it('tokenizes input even if input is the right most element', () => {
- tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
- ${FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label')}
- ${FilteredSearchSpecHelper.createInputHTML('', '~bug')}
- `;
-
- subject.moveInputToTheRight();
-
- const token = tokensContainer.children[1];
-
- expect(token.querySelector('.value').innerText).toEqual('~bug');
- });
- });
-
- describe('renderVisualTokenValue', () => {
- beforeEach(() => {
- tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${authorToken.outerHTML}
- ${bugLabelToken.outerHTML}
- `);
- });
-
- it('renders a author token value element', () => {
- const { tokenNameElement, tokenValueElement } = findElements(authorToken);
- const tokenName = tokenNameElement.innerText;
- const tokenValue = 'new value';
-
- subject.renderVisualTokenValue(authorToken, tokenName, tokenValue);
-
- expect(tokenValueElement.innerText).toBe(tokenValue);
- });
- });
-});
diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js
deleted file mode 100644
index 06f76c581f2..00000000000
--- a/spec/javascripts/gl_dropdown_spec.js
+++ /dev/null
@@ -1,341 +0,0 @@
-/* eslint-disable no-param-reassign */
-
-import $ from 'jquery';
-import GLDropdown from '~/gl_dropdown';
-import '~/lib/utils/common_utils';
-
-describe('glDropdown', function describeDropdown() {
- preloadFixtures('static/gl_dropdown.html');
- loadJSONFixtures('static/projects.json');
-
- const NON_SELECTABLE_CLASSES =
- '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
- const SEARCH_INPUT_SELECTOR = '.dropdown-input-field';
- const ITEM_SELECTOR = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES})`;
- const FOCUSED_ITEM_SELECTOR = `${ITEM_SELECTOR} a.is-focused`;
-
- const ARROW_KEYS = {
- DOWN: 40,
- UP: 38,
- ENTER: 13,
- ESC: 27,
- };
-
- let remoteCallback;
-
- const navigateWithKeys = function navigateWithKeys(direction, steps, cb, i) {
- i = i || 0;
- if (!i) direction = direction.toUpperCase();
- $('body').trigger({
- type: 'keydown',
- which: ARROW_KEYS[direction],
- keyCode: ARROW_KEYS[direction],
- });
- i += 1;
- if (i <= steps) {
- navigateWithKeys(direction, steps, cb, i);
- } else {
- cb();
- }
- };
-
- const remoteMock = function remoteMock(data, term, callback) {
- remoteCallback = callback.bind({}, data);
- };
-
- function initDropDown(hasRemote, isFilterable, extraOpts = {}) {
- const options = {
- selectable: true,
- filterable: isFilterable,
- data: hasRemote ? remoteMock.bind({}, this.projectsData) : this.projectsData,
- search: {
- fields: ['name'],
- },
- text: project => project.name_with_namespace || project.name,
- id: project => project.id,
- ...extraOpts,
- };
- this.dropdownButtonElement = $(
- '#js-project-dropdown',
- this.dropdownContainerElement,
- ).glDropdown(options);
- }
-
- beforeEach(() => {
- loadFixtures('static/gl_dropdown.html');
- this.dropdownContainerElement = $('.dropdown.inline');
- this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement);
- this.projectsData = getJSONFixture('static/projects.json');
- });
-
- afterEach(() => {
- $('body').off('keydown');
- this.dropdownContainerElement.off('keyup');
- });
-
- it('should open on click', () => {
- initDropDown.call(this, false);
-
- expect(this.dropdownContainerElement).not.toHaveClass('show');
- this.dropdownButtonElement.click();
-
- expect(this.dropdownContainerElement).toHaveClass('show');
- });
-
- it('escapes HTML as text', () => {
- this.projectsData[0].name_with_namespace = '<script>alert("testing");</script>';
-
- initDropDown.call(this, false);
-
- this.dropdownButtonElement.click();
-
- expect($('.dropdown-content li:first-child').text()).toBe('<script>alert("testing");</script>');
- });
-
- it('should output HTML when highlighting', () => {
- this.projectsData[0].name_with_namespace = 'testing';
- $('.dropdown-input .dropdown-input-field').val('test');
-
- initDropDown.call(this, false, true, {
- highlight: true,
- });
-
- this.dropdownButtonElement.click();
-
- expect($('.dropdown-content li:first-child').text()).toBe('testing');
-
- expect($('.dropdown-content li:first-child a').html()).toBe(
- '<b>t</b><b>e</b><b>s</b><b>t</b>ing',
- );
- });
-
- describe('that is open', () => {
- beforeEach(() => {
- initDropDown.call(this, false, false);
- this.dropdownButtonElement.click();
- });
-
- it('should select a following item on DOWN keypress', () => {
- expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0);
- const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0;
- navigateWithKeys('down', randomIndex, () => {
- expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
- expect($(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement)).toHaveClass(
- 'is-focused',
- );
- });
- });
-
- it('should select a previous item on UP keypress', () => {
- expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0);
- navigateWithKeys('down', this.projectsData.length - 1, () => {
- expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
- const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 2)) + 0;
- navigateWithKeys('up', randomIndex, () => {
- expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
- expect(
- $(
- `${ITEM_SELECTOR}:eq(${this.projectsData.length - 2 - randomIndex}) a`,
- this.$dropdownMenuElement,
- ),
- ).toHaveClass('is-focused');
- });
- });
- });
-
- it('should click the selected item on ENTER keypress', () => {
- expect(this.dropdownContainerElement).toHaveClass('show');
- const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0;
- navigateWithKeys('down', randomIndex, () => {
- const visitUrl = spyOnDependency(GLDropdown, 'visitUrl').and.stub();
- navigateWithKeys('enter', null, () => {
- expect(this.dropdownContainerElement).not.toHaveClass('show');
- const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement);
-
- expect(link).toHaveClass('is-active');
- const linkedLocation = link.attr('href');
- if (linkedLocation && linkedLocation !== '#') {
- expect(visitUrl).toHaveBeenCalledWith(linkedLocation);
- }
- });
- });
- });
-
- it('should close on ESC keypress', () => {
- expect(this.dropdownContainerElement).toHaveClass('show');
- this.dropdownContainerElement.trigger({
- type: 'keyup',
- which: ARROW_KEYS.ESC,
- keyCode: ARROW_KEYS.ESC,
- });
-
- expect(this.dropdownContainerElement).not.toHaveClass('show');
- });
- });
-
- describe('opened and waiting for a remote callback', () => {
- beforeEach(() => {
- initDropDown.call(this, true, true);
- this.dropdownButtonElement.click();
- });
-
- it('should show loading indicator while search results are being fetched by backend', () => {
- const dropdownMenu = document.querySelector('.dropdown-menu');
-
- expect(dropdownMenu.className.indexOf('is-loading')).not.toBe(-1);
- remoteCallback();
-
- expect(dropdownMenu.className.indexOf('is-loading')).toBe(-1);
- });
-
- it('should not focus search input while remote task is not complete', () => {
- expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR));
- remoteCallback();
-
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
- });
-
- it('should focus search input after remote task is complete', () => {
- remoteCallback();
-
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
- });
-
- it('should focus on input when opening for the second time after transition', () => {
- remoteCallback();
- this.dropdownContainerElement.trigger({
- type: 'keyup',
- which: ARROW_KEYS.ESC,
- keyCode: ARROW_KEYS.ESC,
- });
- this.dropdownButtonElement.click();
- this.dropdownContainerElement.trigger('transitionend');
-
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
- });
- });
-
- describe('input focus with array data', () => {
- it('should focus input when passing array data to drop down', () => {
- initDropDown.call(this, false, true);
- this.dropdownButtonElement.click();
- this.dropdownContainerElement.trigger('transitionend');
-
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
- });
- });
-
- it('should still have input value on close and restore', () => {
- const $searchInput = $(SEARCH_INPUT_SELECTOR);
- initDropDown.call(this, false, true);
- $searchInput
- .trigger('focus')
- .val('g')
- .trigger('input');
-
- expect($searchInput.val()).toEqual('g');
- this.dropdownButtonElement.trigger('hidden.bs.dropdown');
- $searchInput.trigger('blur').trigger('focus');
-
- expect($searchInput.val()).toEqual('g');
- });
-
- describe('renderItem', () => {
- function dropdownWithOptions(options) {
- const $dropdownDiv = $('<div />');
-
- $dropdownDiv.glDropdown(options);
-
- return $dropdownDiv.data('glDropdown');
- }
-
- function basicDropdown() {
- return dropdownWithOptions({});
- }
-
- describe('without selected value', () => {
- let dropdown;
-
- beforeEach(() => {
- dropdown = basicDropdown();
- });
-
- it('marks items without ID as active', () => {
- const dummyData = {};
-
- const html = dropdown.renderItem(dummyData, null, null);
-
- const link = html.querySelector('a');
-
- expect(link).toHaveClass('is-active');
- });
-
- it('does not mark items with ID as active', () => {
- const dummyData = {
- id: 'ea',
- };
-
- const html = dropdown.renderItem(dummyData, null, null);
-
- const link = html.querySelector('a');
-
- expect(link).not.toHaveClass('is-active');
- });
- });
-
- it('should return an empty .separator li when when appropriate', () => {
- const dropdown = basicDropdown();
- const sep = { type: 'separator' };
- const li = dropdown.renderItem(sep);
-
- expect(li).toHaveClass('separator');
- expect(li.childNodes.length).toEqual(0);
- });
-
- it('should return an empty .divider li when when appropriate', () => {
- const dropdown = basicDropdown();
- const div = { type: 'divider' };
- const li = dropdown.renderItem(div);
-
- expect(li).toHaveClass('divider');
- expect(li.childNodes.length).toEqual(0);
- });
-
- it('should return a .dropdown-header li with the correct content when when appropriate', () => {
- const dropdown = basicDropdown();
- const text = 'My Header';
- const header = { type: 'header', content: text };
- const li = dropdown.renderItem(header);
-
- expect(li).toHaveClass('dropdown-header');
- expect(li.childNodes.length).toEqual(1);
- expect(li.textContent).toEqual(text);
- });
- });
-
- it('should keep selected item after selecting a second time', () => {
- const options = {
- isSelectable(item, $el) {
- return !$el.hasClass('is-active');
- },
- toggleLabel(item) {
- return item && item.id;
- },
- };
- initDropDown.call(this, false, false, options);
- const $item = $(`${ITEM_SELECTOR}:first() a`, this.$dropdownMenuElement);
-
- // select item the first time
- this.dropdownButtonElement.click();
- $item.click();
-
- expect($item).toHaveClass('is-active');
- // select item the second time
- this.dropdownButtonElement.click();
- $item.click();
-
- expect($item).toHaveClass('is-active');
-
- expect($('.dropdown-toggle-text')).toHaveText(this.projectsData[0].id.toString());
- });
-});
diff --git a/spec/javascripts/gl_form_spec.js b/spec/javascripts/gl_form_spec.js
deleted file mode 100644
index 69b3dae743a..00000000000
--- a/spec/javascripts/gl_form_spec.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import $ from 'jquery';
-import autosize from 'autosize';
-import GLForm from '~/gl_form';
-import '~/lib/utils/text_utility';
-import '~/lib/utils/common_utils';
-
-describe('GLForm', () => {
- describe('when instantiated', function() {
- beforeEach(done => {
- this.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>');
- this.textarea = this.form.find('textarea');
- spyOn($.prototype, 'off').and.returnValue(this.textarea);
- spyOn($.prototype, 'on').and.returnValue(this.textarea);
- spyOn($.prototype, 'css');
-
- this.glForm = new GLForm(this.form, false);
- setTimeout(() => {
- $.prototype.off.calls.reset();
- $.prototype.on.calls.reset();
- $.prototype.css.calls.reset();
- done();
- });
- });
-
- describe('setupAutosize', () => {
- beforeEach(done => {
- this.glForm.setupAutosize();
- setTimeout(() => {
- done();
- });
- });
-
- it('should register an autosize event handler on the textarea', () => {
- expect($.prototype.off).toHaveBeenCalledWith('autosize:resized');
- expect($.prototype.on).toHaveBeenCalledWith('autosize:resized', jasmine.any(Function));
- });
-
- it('should register a mouseup event handler on the textarea', () => {
- expect($.prototype.off).toHaveBeenCalledWith('mouseup.autosize');
- expect($.prototype.on).toHaveBeenCalledWith('mouseup.autosize', jasmine.any(Function));
- });
-
- it('should set the resize css property to vertical', () => {
- expect($.prototype.css).toHaveBeenCalledWith('resize', 'vertical');
- });
- });
-
- describe('setHeightData', () => {
- beforeEach(() => {
- spyOn($.prototype, 'data');
- spyOn($.prototype, 'outerHeight').and.returnValue(200);
- this.glForm.setHeightData();
- });
-
- it('should set the height data attribute', () => {
- expect($.prototype.data).toHaveBeenCalledWith('height', 200);
- });
-
- it('should call outerHeight', () => {
- expect($.prototype.outerHeight).toHaveBeenCalled();
- });
- });
-
- describe('destroyAutosize', () => {
- describe('when called', () => {
- beforeEach(() => {
- spyOn($.prototype, 'data');
- spyOn($.prototype, 'outerHeight').and.returnValue(200);
- spyOn(window, 'outerHeight').and.returnValue(400);
- spyOn(autosize, 'destroy');
-
- this.glForm.destroyAutosize();
- });
-
- it('should call outerHeight', () => {
- expect($.prototype.outerHeight).toHaveBeenCalled();
- });
-
- it('should get data-height attribute', () => {
- expect($.prototype.data).toHaveBeenCalledWith('height');
- });
-
- it('should call autosize destroy', () => {
- expect(autosize.destroy).toHaveBeenCalledWith(this.textarea);
- });
-
- it('should set the data-height attribute', () => {
- expect($.prototype.data).toHaveBeenCalledWith('height', 200);
- });
-
- it('should set the outerHeight', () => {
- expect($.prototype.outerHeight).toHaveBeenCalledWith(200);
- });
-
- it('should set the css', () => {
- expect($.prototype.css).toHaveBeenCalledWith('max-height', window.outerHeight);
- });
- });
-
- it('should return undefined if the data-height equals the outerHeight', () => {
- spyOn($.prototype, 'outerHeight').and.returnValue(200);
- spyOn($.prototype, 'data').and.returnValue(200);
- spyOn(autosize, 'destroy');
-
- expect(this.glForm.destroyAutosize()).toBeUndefined();
- expect(autosize.destroy).not.toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/spec/javascripts/helpers/scroll_into_view_promise.js b/spec/javascripts/helpers/scroll_into_view_promise.js
deleted file mode 100644
index 0edea2103da..00000000000
--- a/spec/javascripts/helpers/scroll_into_view_promise.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export default function scrollIntoViewPromise(intersectionTarget, timeout = 100, maxTries = 5) {
- return new Promise((resolve, reject) => {
- let intersectionObserver;
- let retry = 0;
-
- const intervalId = setInterval(() => {
- if (retry >= maxTries) {
- intersectionObserver.disconnect();
- clearInterval(intervalId);
- reject(new Error(`Could not scroll target into viewPort within ${timeout * maxTries} ms`));
- }
- retry += 1;
- intersectionTarget.scrollIntoView();
- }, timeout);
-
- intersectionObserver = new IntersectionObserver(entries => {
- if (entries[0].isIntersecting) {
- intersectionObserver.disconnect();
- clearInterval(intervalId);
- resolve();
- }
- });
-
- intersectionObserver.observe(intersectionTarget);
-
- intersectionTarget.scrollIntoView();
- });
-}
diff --git a/spec/javascripts/helpers/vuex_action_helper_spec.js b/spec/javascripts/helpers/vuex_action_helper_spec.js
deleted file mode 100644
index 09f0bd395c3..00000000000
--- a/spec/javascripts/helpers/vuex_action_helper_spec.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import { TEST_HOST } from 'spec/test_constants';
-import axios from '~/lib/utils/axios_utils';
-import testAction from './vuex_action_helper';
-
-describe('VueX test helper (testAction)', () => {
- let originalExpect;
- let assertion;
- let mock;
- const noop = () => {};
-
- beforeAll(() => {
- mock = new MockAdapter(axios);
- /*
- In order to test the helper properly, we need to overwrite the jasmine `expect` helper.
- We test that the testAction helper properly passes the dispatched actions/committed mutations
- to the jasmine helper.
- */
- originalExpect = expect;
- assertion = null;
- global.expect = actual => ({
- toEqual: () => {
- originalExpect(actual).toEqual(assertion);
- },
- });
- });
-
- afterAll(() => {
- mock.restore();
- global.expect = originalExpect;
- });
-
- it('should properly pass on state and payload', () => {
- const exampleState = { FOO: 12, BAR: 3 };
- const examplePayload = { BAZ: 73, BIZ: 55 };
-
- const action = ({ state }, payload) => {
- originalExpect(state).toEqual(exampleState);
- originalExpect(payload).toEqual(examplePayload);
- };
-
- assertion = { mutations: [], actions: [] };
-
- testAction(action, examplePayload, exampleState);
- });
-
- describe('should work with synchronous actions', () => {
- it('committing mutation', () => {
- const action = ({ commit }) => {
- commit('MUTATION');
- };
-
- assertion = { mutations: [{ type: 'MUTATION' }], actions: [] };
-
- testAction(action, null, {}, assertion.mutations, assertion.actions, noop);
- });
-
- it('dispatching action', () => {
- const action = ({ dispatch }) => {
- dispatch('ACTION');
- };
-
- assertion = { actions: [{ type: 'ACTION' }], mutations: [] };
-
- testAction(action, null, {}, assertion.mutations, assertion.actions, noop);
- });
-
- it('work with jasmine done once finished', done => {
- assertion = { mutations: [], actions: [] };
-
- testAction(noop, null, {}, assertion.mutations, assertion.actions, done);
- });
-
- it('provide promise interface', done => {
- assertion = { mutations: [], actions: [] };
-
- testAction(noop, null, {}, assertion.mutations, assertion.actions)
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('should work with promise based actions (fetch action)', () => {
- let lastError;
- const data = { FOO: 'BAR' };
-
- const promiseAction = ({ commit, dispatch }) => {
- dispatch('ACTION');
-
- return axios
- .get(TEST_HOST)
- .catch(error => {
- commit('ERROR');
- lastError = error;
- throw error;
- })
- .then(() => {
- commit('SUCCESS');
- return data;
- });
- };
-
- beforeEach(() => {
- lastError = null;
- });
-
- it('work with jasmine done once finished', done => {
- mock.onGet(TEST_HOST).replyOnce(200, 42);
-
- assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
-
- testAction(promiseAction, null, {}, assertion.mutations, assertion.actions, done);
- });
-
- it('return original data of successful promise while checking actions/mutations', done => {
- mock.onGet(TEST_HOST).replyOnce(200, 42);
-
- assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
-
- testAction(promiseAction, null, {}, assertion.mutations, assertion.actions)
- .then(res => {
- originalExpect(res).toEqual(data);
- done();
- })
- .catch(done.fail);
- });
-
- it('return original error of rejected promise while checking actions/mutations', done => {
- mock.onGet(TEST_HOST).replyOnce(500, '');
-
- assertion = { mutations: [{ type: 'ERROR' }], actions: [{ type: 'ACTION' }] };
-
- testAction(promiseAction, null, {}, assertion.mutations, assertion.actions)
- .then(done.fail)
- .catch(error => {
- originalExpect(error).toBe(lastError);
- done();
- });
- });
- });
-
- it('should work with async actions not returning promises', done => {
- const data = { FOO: 'BAR' };
-
- const promiseAction = ({ commit, dispatch }) => {
- dispatch('ACTION');
-
- axios
- .get(TEST_HOST)
- .then(() => {
- commit('SUCCESS');
- return data;
- })
- .catch(error => {
- commit('ERROR');
- throw error;
- });
- };
-
- mock.onGet(TEST_HOST).replyOnce(200, 42);
-
- assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
-
- testAction(promiseAction, null, {}, assertion.mutations, assertion.actions, done);
- });
-});
diff --git a/spec/javascripts/helpers/wait_for_attribute_change.js b/spec/javascripts/helpers/wait_for_attribute_change.js
deleted file mode 100644
index 8f22d569222..00000000000
--- a/spec/javascripts/helpers/wait_for_attribute_change.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export default (domElement, attributes, timeout = 1500) =>
- new Promise((resolve, reject) => {
- let observer;
- const timeoutId = setTimeout(() => {
- observer.disconnect();
- reject(new Error(`Could not see an attribute update within ${timeout} ms`));
- }, timeout);
-
- observer = new MutationObserver(() => {
- clearTimeout(timeoutId);
- observer.disconnect();
- resolve();
- });
-
- observer.observe(domElement, { attributes: true, attributeFilter: attributes });
- });
diff --git a/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js b/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js
deleted file mode 100644
index 53508f52b2f..00000000000
--- a/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js
+++ /dev/null
@@ -1,170 +0,0 @@
-import Vue from 'vue';
-import createComponent from 'spec/helpers/vue_mount_component_helper';
-import CommitMessageField from '~/ide/components/commit_sidebar/message_field.vue';
-
-describe('IDE commit message field', () => {
- const Component = Vue.extend(CommitMessageField);
- let vm;
-
- beforeEach(() => {
- setFixtures('<div id="app"></div>');
-
- vm = createComponent(
- Component,
- {
- text: '',
- placeholder: 'testing',
- },
- '#app',
- );
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('adds is-focused class on focus', done => {
- vm.$el.querySelector('textarea').focus();
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.is-focused')).not.toBeNull();
-
- done();
- });
- });
-
- it('removed is-focused class on blur', done => {
- vm.$el.querySelector('textarea').focus();
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.is-focused')).not.toBeNull();
-
- vm.$el.querySelector('textarea').blur();
-
- return vm.$nextTick();
- })
- .then(() => {
- expect(vm.$el.querySelector('.is-focused')).toBeNull();
-
- done();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('emits input event on input', () => {
- spyOn(vm, '$emit');
-
- const textarea = vm.$el.querySelector('textarea');
- textarea.value = 'testing';
-
- textarea.dispatchEvent(new Event('input'));
-
- expect(vm.$emit).toHaveBeenCalledWith('input', 'testing');
- });
-
- describe('highlights', () => {
- describe('subject line', () => {
- it('does not highlight less than 50 characters', done => {
- vm.text = 'text less than 50 chars';
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.highlights span').textContent).toContain(
- 'text less than 50 chars',
- );
-
- expect(vm.$el.querySelector('mark').style.display).toBe('none');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('highlights characters over 50 length', done => {
- vm.text =
- 'text less than 50 chars that should not highlighted. text more than 50 should be highlighted';
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.highlights span').textContent).toContain(
- 'text less than 50 chars that should not highlighte',
- );
-
- expect(vm.$el.querySelector('mark').style.display).not.toBe('none');
- expect(vm.$el.querySelector('mark').textContent).toBe(
- 'd. text more than 50 should be highlighted',
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('body text', () => {
- it('does not highlight body text less tan 72 characters', done => {
- vm.text = 'subject line\nbody content';
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark')[1].style.display).toBe('none');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('highlights body text more than 72 characters', done => {
- vm.text =
- 'subject line\nbody content that will be highlighted when it is more than 72 characters in length';
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark')[1].style.display).not.toBe('none');
- expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('highlights body text & subject line', done => {
- vm.text =
- 'text less than 50 chars that should not highlighted\nbody content that will be highlighted when it is more than 72 characters in length';
-
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark').length).toBe(2);
-
- expect(vm.$el.querySelectorAll('mark')[0].textContent).toContain('d');
- expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length');
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
-
- describe('scrolling textarea', () => {
- it('updates transform of highlights', done => {
- vm.text = 'subject line\n\n\n\n\n\n\n\n\n\n\nbody content';
-
- vm.$nextTick()
- .then(() => {
- vm.$el.querySelector('textarea').scrollTo(0, 50);
-
- vm.handleScroll();
- })
- .then(vm.$nextTick)
- .then(() => {
- expect(vm.scrollTop).toBe(50);
- expect(vm.$el.querySelector('.highlights').style.transform).toBe(
- 'translate3d(0px, -50px, 0px)',
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/javascripts/ide/components/jobs/detail_spec.js b/spec/javascripts/ide/components/jobs/detail_spec.js
deleted file mode 100644
index a4e6b81acba..00000000000
--- a/spec/javascripts/ide/components/jobs/detail_spec.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import Vue from 'vue';
-import JobDetail from '~/ide/components/jobs/detail.vue';
-import { createStore } from '~/ide/stores';
-import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
-import { jobs } from '../../mock_data';
-
-describe('IDE jobs detail view', () => {
- const Component = Vue.extend(JobDetail);
- let vm;
-
- beforeEach(() => {
- const store = createStore();
-
- store.state.pipelines.detailJob = {
- ...jobs[0],
- isLoading: true,
- output: 'testing',
- rawPath: `${gl.TEST_HOST}/raw`,
- };
-
- vm = createComponentWithStore(Component, store);
-
- spyOn(vm, 'fetchJobTrace').and.returnValue(Promise.resolve());
-
- vm = vm.$mount();
-
- spyOn(vm.$refs.buildTrace, 'scrollTo');
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('calls fetchJobTrace on mount', () => {
- expect(vm.fetchJobTrace).toHaveBeenCalled();
- });
-
- it('scrolls to bottom on mount', done => {
- setTimeout(() => {
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('renders job output', () => {
- expect(vm.$el.querySelector('.bash').textContent).toContain('testing');
- });
-
- it('renders empty message output', done => {
- vm.$store.state.pipelines.detailJob.output = '';
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.bash').textContent).toContain('No messages were logged');
-
- done();
- });
- });
-
- it('renders loading icon', () => {
- expect(vm.$el.querySelector('.build-loader-animation')).not.toBe(null);
- expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('');
- });
-
- it('hides output when loading', () => {
- expect(vm.$el.querySelector('.bash')).not.toBe(null);
- expect(vm.$el.querySelector('.bash').style.display).toBe('none');
- });
-
- it('hide loading icon when isLoading is false', done => {
- vm.$store.state.pipelines.detailJob.isLoading = false;
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('none');
-
- done();
- });
- });
-
- it('resets detailJob when clicking header button', () => {
- spyOn(vm, 'setDetailJob');
-
- vm.$el.querySelector('.btn').click();
-
- expect(vm.setDetailJob).toHaveBeenCalledWith(null);
- });
-
- it('renders raw path link', () => {
- expect(vm.$el.querySelector('.controllers-buttons').getAttribute('href')).toBe(
- `${gl.TEST_HOST}/raw`,
- );
- });
-
- describe('scroll buttons', () => {
- it('triggers scrollDown when clicking down button', done => {
- spyOn(vm, 'scrollDown');
-
- vm.$el.querySelectorAll('.btn-scroll')[1].click();
-
- vm.$nextTick(() => {
- expect(vm.scrollDown).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('triggers scrollUp when clicking up button', done => {
- spyOn(vm, 'scrollUp');
-
- vm.scrollPos = 1;
-
- vm.$nextTick()
- .then(() => vm.$el.querySelector('.btn-scroll').click())
- .then(() => vm.$nextTick())
- .then(() => {
- expect(vm.scrollUp).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('scrollDown', () => {
- it('scrolls build trace to bottom', () => {
- spyOnProperty(vm.$refs.buildTrace, 'scrollHeight').and.returnValue(1000);
-
- vm.scrollDown();
-
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 1000);
- });
- });
-
- describe('scrollUp', () => {
- it('scrolls build trace to top', () => {
- vm.scrollUp();
-
- expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 0);
- });
- });
-
- describe('scrollBuildLog', () => {
- beforeEach(() => {
- spyOnProperty(vm.$refs.buildTrace, 'offsetHeight').and.returnValue(100);
- spyOnProperty(vm.$refs.buildTrace, 'scrollHeight').and.returnValue(200);
- });
-
- it('sets scrollPos to bottom when at the bottom', done => {
- spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(100);
-
- vm.scrollBuildLog();
-
- setTimeout(() => {
- expect(vm.scrollPos).toBe(1);
-
- done();
- });
- });
-
- it('sets scrollPos to top when at the top', done => {
- spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(0);
- vm.scrollPos = 1;
-
- vm.scrollBuildLog();
-
- setTimeout(() => {
- expect(vm.scrollPos).toBe(0);
-
- done();
- });
- });
-
- it('resets scrollPos when not at top or bottom', done => {
- spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(10);
-
- vm.scrollBuildLog();
-
- setTimeout(() => {
- expect(vm.scrollPos).toBe('');
-
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js
deleted file mode 100644
index 8db29011da7..00000000000
--- a/spec/javascripts/ide/components/repo_editor_spec.js
+++ /dev/null
@@ -1,512 +0,0 @@
-import Vue from 'vue';
-import MockAdapter from 'axios-mock-adapter';
-import '~/behaviors/markdown/render_gfm';
-import axios from '~/lib/utils/axios_utils';
-import store from '~/ide/stores';
-import repoEditor from '~/ide/components/repo_editor.vue';
-import Editor from '~/ide/lib/editor';
-import { leftSidebarViews, FILE_VIEW_MODE_EDITOR, FILE_VIEW_MODE_PREVIEW } from '~/ide/constants';
-import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
-import setTimeoutPromise from '../../helpers/set_timeout_promise_helper';
-import { file, resetStore } from '../helpers';
-
-describe('RepoEditor', () => {
- let vm;
-
- beforeEach(done => {
- const f = {
- ...file(),
- viewMode: FILE_VIEW_MODE_EDITOR,
- };
- const RepoEditor = Vue.extend(repoEditor);
-
- vm = createComponentWithStore(RepoEditor, store, {
- file: f,
- });
-
- f.active = true;
- f.tempFile = true;
-
- vm.$store.state.openFiles.push(f);
- vm.$store.state.projects = {
- 'gitlab-org/gitlab': {
- branches: {
- master: {
- name: 'master',
- commit: {
- id: 'abcdefgh',
- },
- },
- },
- },
- };
- vm.$store.state.currentProjectId = 'gitlab-org/gitlab';
- vm.$store.state.currentBranchId = 'master';
-
- Vue.set(vm.$store.state.entries, f.path, f);
-
- spyOn(vm, 'getFileData').and.returnValue(Promise.resolve());
- spyOn(vm, 'getRawFileData').and.returnValue(Promise.resolve());
-
- vm.$mount();
-
- Vue.nextTick(() => setTimeout(done));
- });
-
- afterEach(() => {
- vm.$destroy();
-
- resetStore(vm.$store);
-
- Editor.editorInstance.dispose();
- });
-
- const findEditor = () => vm.$el.querySelector('.multi-file-editor-holder');
-
- it('sets renderWhitespace to `all`', () => {
- vm.$store.state.renderWhitespaceInCode = true;
-
- expect(vm.editorOptions.renderWhitespace).toEqual('all');
- });
-
- it('sets renderWhitespace to `none`', () => {
- vm.$store.state.renderWhitespaceInCode = false;
-
- expect(vm.editorOptions.renderWhitespace).toEqual('none');
- });
-
- it('renders an ide container', () => {
- expect(vm.shouldHideEditor).toBeFalsy();
- expect(vm.showEditor).toBe(true);
- expect(findEditor()).not.toHaveCss({ display: 'none' });
- });
-
- it('renders only an edit tab', done => {
- Vue.nextTick(() => {
- const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li');
-
- expect(tabs.length).toBe(1);
- expect(tabs[0].textContent.trim()).toBe('Edit');
-
- done();
- });
- });
-
- describe('when file is markdown', () => {
- beforeEach(done => {
- vm.file.previewMode = {
- id: 'markdown',
- previewTitle: 'Preview Markdown',
- };
-
- vm.$nextTick(done);
- });
-
- it('renders an Edit and a Preview Tab', done => {
- Vue.nextTick(() => {
- const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li');
-
- expect(tabs.length).toBe(2);
- expect(tabs[0].textContent.trim()).toBe('Edit');
- expect(tabs[1].textContent.trim()).toBe('Preview Markdown');
-
- done();
- });
- });
- });
-
- describe('when file is markdown and viewer mode is review', () => {
- let mock;
-
- beforeEach(done => {
- mock = new MockAdapter(axios);
-
- vm.file.projectId = 'namespace/project';
- vm.file.previewMode = {
- id: 'markdown',
- previewTitle: 'Preview Markdown',
- };
- vm.file.content = 'testing 123';
- vm.$store.state.viewer = 'diff';
-
- mock.onPost(/(.*)\/preview_markdown/).reply(200, {
- body: '<p>testing 123</p>',
- });
-
- vm.$nextTick(done);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('renders an Edit and a Preview Tab', done => {
- Vue.nextTick(() => {
- const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li');
-
- expect(tabs.length).toBe(2);
- expect(tabs[0].textContent.trim()).toBe('Review');
- expect(tabs[1].textContent.trim()).toBe('Preview Markdown');
-
- done();
- });
- });
-
- it('renders markdown for tempFile', done => {
- vm.file.tempFile = true;
- vm.file.path = `${vm.file.path}.md`;
- vm.$store.state.entries[vm.file.path] = vm.file;
-
- vm.$nextTick()
- .then(() => {
- vm.$el.querySelectorAll('.ide-mode-tabs .nav-links a')[1].click();
- })
- .then(setTimeoutPromise)
- .then(() => {
- expect(vm.$el.querySelector('.preview-container').innerHTML).toContain(
- '<p>testing 123</p>',
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('when open file is binary and not raw', () => {
- beforeEach(done => {
- vm.file.binary = true;
-
- vm.$nextTick(done);
- });
-
- it('does not render the IDE', () => {
- expect(vm.shouldHideEditor).toBeTruthy();
- });
- });
-
- describe('createEditorInstance', () => {
- it('calls createInstance when viewer is editor', done => {
- spyOn(vm.editor, 'createInstance');
-
- vm.createEditorInstance();
-
- vm.$nextTick(() => {
- expect(vm.editor.createInstance).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('calls createDiffInstance when viewer is diff', done => {
- vm.$store.state.viewer = 'diff';
-
- spyOn(vm.editor, 'createDiffInstance');
-
- vm.createEditorInstance();
-
- vm.$nextTick(() => {
- expect(vm.editor.createDiffInstance).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('calls createDiffInstance when viewer is a merge request diff', done => {
- vm.$store.state.viewer = 'mrdiff';
-
- spyOn(vm.editor, 'createDiffInstance');
-
- vm.createEditorInstance();
-
- vm.$nextTick(() => {
- expect(vm.editor.createDiffInstance).toHaveBeenCalled();
-
- done();
- });
- });
- });
-
- describe('setupEditor', () => {
- it('creates new model', () => {
- spyOn(vm.editor, 'createModel').and.callThrough();
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.setupEditor();
-
- expect(vm.editor.createModel).toHaveBeenCalledWith(vm.file, null);
- expect(vm.model).not.toBeNull();
- });
-
- it('attaches model to editor', () => {
- spyOn(vm.editor, 'attachModel').and.callThrough();
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.setupEditor();
-
- expect(vm.editor.attachModel).toHaveBeenCalledWith(vm.model);
- });
-
- it('attaches model to merge request editor', () => {
- vm.$store.state.viewer = 'mrdiff';
- vm.file.mrChange = true;
- spyOn(vm.editor, 'attachMergeRequestModel');
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.setupEditor();
-
- expect(vm.editor.attachMergeRequestModel).toHaveBeenCalledWith(vm.model);
- });
-
- it('does not attach model to merge request editor when not a MR change', () => {
- vm.$store.state.viewer = 'mrdiff';
- vm.file.mrChange = false;
- spyOn(vm.editor, 'attachMergeRequestModel');
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.setupEditor();
-
- expect(vm.editor.attachMergeRequestModel).not.toHaveBeenCalledWith(vm.model);
- });
-
- it('adds callback methods', () => {
- spyOn(vm.editor, 'onPositionChange').and.callThrough();
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.setupEditor();
-
- expect(vm.editor.onPositionChange).toHaveBeenCalled();
- expect(vm.model.events.size).toBe(2);
- });
-
- it('updates state when model content changed', done => {
- vm.model.setValue('testing 123\n');
-
- setTimeout(() => {
- expect(vm.file.content).toBe('testing 123\n');
-
- done();
- });
- });
-
- it('sets head model as staged file', () => {
- spyOn(vm.editor, 'createModel').and.callThrough();
-
- Editor.editorInstance.modelManager.dispose();
-
- vm.$store.state.stagedFiles.push({ ...vm.file, key: 'staged' });
- vm.file.staged = true;
- vm.file.key = `unstaged-${vm.file.key}`;
-
- vm.setupEditor();
-
- expect(vm.editor.createModel).toHaveBeenCalledWith(vm.file, vm.$store.state.stagedFiles[0]);
- });
- });
-
- describe('editor updateDimensions', () => {
- beforeEach(() => {
- spyOn(vm.editor, 'updateDimensions').and.callThrough();
- spyOn(vm.editor, 'updateDiffView');
- });
-
- it('calls updateDimensions when panelResizing is false', done => {
- vm.$store.state.panelResizing = true;
-
- vm.$nextTick()
- .then(() => {
- vm.$store.state.panelResizing = false;
- })
- .then(vm.$nextTick)
- .then(() => {
- expect(vm.editor.updateDimensions).toHaveBeenCalled();
- expect(vm.editor.updateDiffView).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('does not call updateDimensions when panelResizing is true', done => {
- vm.$store.state.panelResizing = true;
-
- vm.$nextTick(() => {
- expect(vm.editor.updateDimensions).not.toHaveBeenCalled();
- expect(vm.editor.updateDiffView).not.toHaveBeenCalled();
-
- done();
- });
- });
-
- it('calls updateDimensions when rightPane is opened', done => {
- vm.$store.state.rightPane.isOpen = true;
-
- vm.$nextTick(() => {
- expect(vm.editor.updateDimensions).toHaveBeenCalled();
- expect(vm.editor.updateDiffView).toHaveBeenCalled();
-
- done();
- });
- });
- });
-
- describe('show tabs', () => {
- it('shows tabs in edit mode', () => {
- expect(vm.$el.querySelector('.nav-links')).not.toBe(null);
- });
-
- it('hides tabs in review mode', done => {
- vm.$store.state.currentActivityView = leftSidebarViews.review.name;
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.nav-links')).toBe(null);
-
- done();
- });
- });
-
- it('hides tabs in commit mode', done => {
- vm.$store.state.currentActivityView = leftSidebarViews.commit.name;
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.nav-links')).toBe(null);
-
- done();
- });
- });
- });
-
- describe('when files view mode is preview', () => {
- beforeEach(done => {
- spyOn(vm.editor, 'updateDimensions');
- vm.file.viewMode = FILE_VIEW_MODE_PREVIEW;
- vm.$nextTick(done);
- });
-
- it('should hide editor', () => {
- expect(vm.showEditor).toBe(false);
- expect(findEditor()).toHaveCss({ display: 'none' });
- });
-
- describe('when file view mode changes to editor', () => {
- beforeEach(done => {
- vm.file.viewMode = FILE_VIEW_MODE_EDITOR;
-
- // one tick to trigger watch
- vm.$nextTick()
- // another tick needed until we can update dimensions
- .then(() => vm.$nextTick())
- .then(done)
- .catch(done.fail);
- });
-
- it('should update dimensions', () => {
- expect(vm.editor.updateDimensions).toHaveBeenCalled();
- });
- });
- });
-
- describe('initEditor', () => {
- beforeEach(() => {
- vm.file.tempFile = false;
- spyOn(vm.editor, 'createInstance');
- spyOnProperty(vm, 'shouldHideEditor').and.returnValue(true);
- });
-
- it('does not fetch file information for temp entries', done => {
- vm.file.tempFile = true;
-
- vm.initEditor();
- vm.$nextTick()
- .then(() => {
- expect(vm.getFileData).not.toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('is being initialised for files without content even if shouldHideEditor is `true`', done => {
- vm.file.content = '';
- vm.file.raw = '';
-
- vm.initEditor();
- vm.$nextTick()
- .then(() => {
- expect(vm.getFileData).toHaveBeenCalled();
- expect(vm.getRawFileData).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('does not initialize editor for files already with content', done => {
- vm.file.content = 'foo';
-
- vm.initEditor();
- vm.$nextTick()
- .then(() => {
- expect(vm.getFileData).not.toHaveBeenCalled();
- expect(vm.getRawFileData).not.toHaveBeenCalled();
- expect(vm.editor.createInstance).not.toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('updates on file changes', () => {
- beforeEach(() => {
- spyOn(vm, 'initEditor');
- });
-
- it('calls removePendingTab when old file is pending', done => {
- spyOnProperty(vm, 'shouldHideEditor').and.returnValue(true);
- spyOn(vm, 'removePendingTab');
-
- vm.file.pending = true;
-
- vm.$nextTick()
- .then(() => {
- vm.file = file('testing');
- vm.file.content = 'foo'; // need to prevent full cycle of initEditor
-
- return vm.$nextTick();
- })
- .then(() => {
- expect(vm.removePendingTab).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('does not call initEditor if the file did not change', done => {
- Vue.set(vm, 'file', vm.file);
-
- vm.$nextTick()
- .then(() => {
- expect(vm.initEditor).not.toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('calls initEditor when file key is changed', done => {
- expect(vm.initEditor).not.toHaveBeenCalled();
-
- Vue.set(vm, 'file', {
- ...vm.file,
- key: 'new',
- });
-
- vm.$nextTick()
- .then(() => {
- expect(vm.initEditor).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
deleted file mode 100644
index 2c52780f316..00000000000
--- a/spec/javascripts/ide/helpers.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from '../../frontend/ide/helpers';
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
deleted file mode 100644
index 27f0ad01f54..00000000000
--- a/spec/javascripts/ide/mock_data.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from '../../frontend/ide/mock_data';
diff --git a/spec/javascripts/ide/stores/actions/merge_request_spec.js b/spec/javascripts/ide/stores/actions/merge_request_spec.js
deleted file mode 100644
index ce09cf51ac5..00000000000
--- a/spec/javascripts/ide/stores/actions/merge_request_spec.js
+++ /dev/null
@@ -1,510 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import store from '~/ide/stores';
-import actions, {
- getMergeRequestData,
- getMergeRequestChanges,
- getMergeRequestVersions,
- openMergeRequest,
-} from '~/ide/stores/actions/merge_request';
-import service from '~/ide/services';
-import { leftSidebarViews, PERMISSION_READ_MR } from '~/ide/constants';
-import { resetStore } from '../../helpers';
-
-const TEST_PROJECT = 'abcproject';
-const TEST_PROJECT_ID = 17;
-
-describe('IDE store merge request actions', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- store.state.projects[TEST_PROJECT] = {
- id: TEST_PROJECT_ID,
- mergeRequests: {},
- userPermissions: {
- [PERMISSION_READ_MR]: true,
- },
- };
- });
-
- afterEach(() => {
- mock.restore();
- resetStore(store);
- });
-
- describe('getMergeRequestsForBranch', () => {
- describe('success', () => {
- const mrData = { iid: 2, source_branch: 'bar' };
- const mockData = [mrData];
-
- describe('base case', () => {
- beforeEach(() => {
- spyOn(service, 'getProjectMergeRequests').and.callThrough();
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).reply(200, mockData);
- });
-
- it('calls getProjectMergeRequests service method', done => {
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
- .then(() => {
- expect(service.getProjectMergeRequests).toHaveBeenCalledWith(TEST_PROJECT, {
- source_branch: 'bar',
- source_project_id: TEST_PROJECT_ID,
- order_by: 'created_at',
- per_page: 1,
- });
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets the "Merge Request" Object', done => {
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
- .then(() => {
- expect(store.state.projects.abcproject.mergeRequests).toEqual({
- '2': jasmine.objectContaining(mrData),
- });
- done();
- })
- .catch(done.fail);
- });
-
- it('sets "Current Merge Request" object to the most recent MR', done => {
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
- .then(() => {
- expect(store.state.currentMergeRequestId).toEqual('2');
- done();
- })
- .catch(done.fail);
- });
-
- it('does nothing if user cannot read MRs', done => {
- store.state.projects[TEST_PROJECT].userPermissions[PERMISSION_READ_MR] = false;
-
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
- .then(() => {
- expect(service.getProjectMergeRequests).not.toHaveBeenCalled();
- expect(store.state.currentMergeRequestId).toBe('');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('no merge requests for branch available case', () => {
- beforeEach(() => {
- spyOn(service, 'getProjectMergeRequests').and.callThrough();
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).reply(200, []);
- });
-
- it('does not fail if there are no merge requests for current branch', done => {
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'foo' })
- .then(() => {
- expect(store.state.projects[TEST_PROJECT].mergeRequests).toEqual({});
- expect(store.state.currentMergeRequestId).toEqual('');
- done();
- })
- .catch(done.fail);
- });
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).networkError();
- });
-
- it('flashes message, if error', done => {
- const flashSpy = spyOnDependency(actions, 'flash');
-
- store
- .dispatch('getMergeRequestsForBranch', { projectId: TEST_PROJECT, branchId: 'bar' })
- .then(() => {
- fail('Expected getMergeRequestsForBranch to throw an error');
- })
- .catch(() => {
- expect(flashSpy).toHaveBeenCalled();
- expect(flashSpy.calls.argsFor(0)[0]).toEqual('Error fetching merge requests for bar');
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
-
- describe('getMergeRequestData', () => {
- describe('success', () => {
- beforeEach(() => {
- spyOn(service, 'getProjectMergeRequestData').and.callThrough();
-
- mock
- .onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1/)
- .reply(200, { title: 'mergerequest' });
- });
-
- it('calls getProjectMergeRequestData service method', done => {
- store
- .dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(service.getProjectMergeRequestData).toHaveBeenCalledWith(TEST_PROJECT, 1);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets the Merge Request Object', done => {
- store
- .dispatch('getMergeRequestData', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(store.state.currentMergeRequestId).toBe(1);
- expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].title).toBe(
- 'mergerequest',
- );
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1/).networkError();
- });
-
- it('dispatches error action', done => {
- const dispatch = jasmine.createSpy('dispatch');
-
- getMergeRequestData(
- {
- commit() {},
- dispatch,
- state: store.state,
- },
- { projectId: TEST_PROJECT, mergeRequestId: 1 },
- )
- .then(done.fail)
- .catch(() => {
- expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
- text: 'An error occurred while loading the merge request.',
- action: jasmine.any(Function),
- actionText: 'Please try again',
- actionPayload: {
- projectId: TEST_PROJECT,
- mergeRequestId: 1,
- force: false,
- },
- });
-
- done();
- });
- });
- });
- });
-
- describe('getMergeRequestChanges', () => {
- beforeEach(() => {
- store.state.projects[TEST_PROJECT].mergeRequests['1'] = { changes: [] };
- });
-
- describe('success', () => {
- beforeEach(() => {
- spyOn(service, 'getProjectMergeRequestChanges').and.callThrough();
-
- mock
- .onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/changes/)
- .reply(200, { title: 'mergerequest' });
- });
-
- it('calls getProjectMergeRequestChanges service method', done => {
- store
- .dispatch('getMergeRequestChanges', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(service.getProjectMergeRequestChanges).toHaveBeenCalledWith(TEST_PROJECT, 1);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets the Merge Request Changes Object', done => {
- store
- .dispatch('getMergeRequestChanges', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].changes.title).toBe(
- 'mergerequest',
- );
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/changes/).networkError();
- });
-
- it('dispatches error action', done => {
- const dispatch = jasmine.createSpy('dispatch');
-
- getMergeRequestChanges(
- {
- commit() {},
- dispatch,
- state: store.state,
- },
- { projectId: TEST_PROJECT, mergeRequestId: 1 },
- )
- .then(done.fail)
- .catch(() => {
- expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
- text: 'An error occurred while loading the merge request changes.',
- action: jasmine.any(Function),
- actionText: 'Please try again',
- actionPayload: {
- projectId: TEST_PROJECT,
- mergeRequestId: 1,
- force: false,
- },
- });
-
- done();
- });
- });
- });
- });
-
- describe('getMergeRequestVersions', () => {
- beforeEach(() => {
- store.state.projects[TEST_PROJECT].mergeRequests['1'] = { versions: [] };
- });
-
- describe('success', () => {
- beforeEach(() => {
- mock
- .onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/versions/)
- .reply(200, [{ id: 789 }]);
- spyOn(service, 'getProjectMergeRequestVersions').and.callThrough();
- });
-
- it('calls getProjectMergeRequestVersions service method', done => {
- store
- .dispatch('getMergeRequestVersions', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(service.getProjectMergeRequestVersions).toHaveBeenCalledWith(TEST_PROJECT, 1);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets the Merge Request Versions Object', done => {
- store
- .dispatch('getMergeRequestVersions', { projectId: TEST_PROJECT, mergeRequestId: 1 })
- .then(() => {
- expect(store.state.projects[TEST_PROJECT].mergeRequests['1'].versions.length).toBe(1);
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests\/1\/versions/).networkError();
- });
-
- it('dispatches error action', done => {
- const dispatch = jasmine.createSpy('dispatch');
-
- getMergeRequestVersions(
- {
- commit() {},
- dispatch,
- state: store.state,
- },
- { projectId: TEST_PROJECT, mergeRequestId: 1 },
- )
- .then(done.fail)
- .catch(() => {
- expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
- text: 'An error occurred while loading the merge request version data.',
- action: jasmine.any(Function),
- actionText: 'Please try again',
- actionPayload: {
- projectId: TEST_PROJECT,
- mergeRequestId: 1,
- force: false,
- },
- });
-
- done();
- });
- });
- });
- });
-
- describe('openMergeRequest', () => {
- const mr = {
- projectId: TEST_PROJECT,
- targetProjectId: 'defproject',
- mergeRequestId: 2,
- };
- let testMergeRequest;
- let testMergeRequestChanges;
-
- const mockGetters = { findBranch: () => ({ commit: { id: 'abcd2322' } }) };
-
- beforeEach(() => {
- testMergeRequest = {
- source_branch: 'abcbranch',
- };
- testMergeRequestChanges = {
- changes: [],
- };
- store.state.entries = {
- foo: {
- type: 'blob',
- },
- bar: {
- type: 'blob',
- },
- };
-
- store.state.currentProjectId = 'test/test';
- store.state.currentBranchId = 'master';
-
- store.state.projects['test/test'] = {
- branches: {
- master: {
- commit: {
- id: '7297abc',
- },
- },
- abcbranch: {
- commit: {
- id: '29020fc',
- },
- },
- },
- };
-
- const originalDispatch = store.dispatch;
-
- spyOn(store, 'dispatch').and.callFake((type, payload) => {
- switch (type) {
- case 'getMergeRequestData':
- return Promise.resolve(testMergeRequest);
- case 'getMergeRequestChanges':
- return Promise.resolve(testMergeRequestChanges);
- case 'getFiles':
- case 'getMergeRequestVersions':
- case 'getBranchData':
- case 'setFileMrChange':
- return Promise.resolve();
- default:
- return originalDispatch(type, payload);
- }
- });
- spyOn(service, 'getFileData').and.callFake(() =>
- Promise.resolve({
- headers: {},
- }),
- );
- });
-
- it('dispatches actions for merge request data', done => {
- openMergeRequest({ state: store.state, dispatch: store.dispatch, getters: mockGetters }, mr)
- .then(() => {
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['getMergeRequestData', mr],
- ['setCurrentBranchId', testMergeRequest.source_branch],
- [
- 'getBranchData',
- {
- projectId: mr.projectId,
- branchId: testMergeRequest.source_branch,
- },
- ],
- [
- 'getFiles',
- {
- projectId: mr.projectId,
- branchId: testMergeRequest.source_branch,
- ref: 'abcd2322',
- },
- ],
- ['getMergeRequestVersions', mr],
- ['getMergeRequestChanges', mr],
- ]);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('updates activity bar view and gets file data, if changes are found', done => {
- store.state.entries.foo = {
- url: 'test',
- type: 'blob',
- };
- store.state.entries.bar = {
- url: 'test',
- type: 'blob',
- };
-
- testMergeRequestChanges.changes = [
- { new_path: 'foo', path: 'foo' },
- { new_path: 'bar', path: 'bar' },
- ];
-
- openMergeRequest({ state: store.state, dispatch: store.dispatch, getters: mockGetters }, mr)
- .then(() => {
- expect(store.dispatch).toHaveBeenCalledWith(
- 'updateActivityBarView',
- leftSidebarViews.review.name,
- );
-
- testMergeRequestChanges.changes.forEach((change, i) => {
- expect(store.dispatch).toHaveBeenCalledWith('setFileMrChange', {
- file: store.state.entries[change.new_path],
- mrChange: change,
- });
-
- expect(store.dispatch).toHaveBeenCalledWith('getFileData', {
- path: change.new_path,
- makeFileActive: i === 0,
- openFile: true,
- });
- });
-
- expect(store.state.openFiles.length).toBe(testMergeRequestChanges.changes.length);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('flashes message, if error', done => {
- const flashSpy = spyOnDependency(actions, 'flash');
- store.dispatch.and.returnValue(Promise.reject());
-
- openMergeRequest(store, mr)
- .then(() => {
- fail('Expected openMergeRequest to throw an error');
- })
- .catch(() => {
- expect(flashSpy).toHaveBeenCalledWith(jasmine.any(String));
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js
deleted file mode 100644
index e962224d1ad..00000000000
--- a/spec/javascripts/ide/stores/actions/project_spec.js
+++ /dev/null
@@ -1,404 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import {
- refreshLastCommitData,
- showBranchNotFoundError,
- createNewBranchFromDefault,
- loadEmptyBranch,
- openBranch,
- loadFile,
- loadBranch,
-} from '~/ide/stores/actions';
-import { createStore } from '~/ide/stores';
-import service from '~/ide/services';
-import api from '~/api';
-import router from '~/ide/ide_router';
-import { resetStore } from '../../helpers';
-import testAction from '../../../helpers/vuex_action_helper';
-
-const TEST_PROJECT_ID = 'abc/def';
-
-describe('IDE store project actions', () => {
- let mock;
- let store;
-
- beforeEach(() => {
- store = createStore();
- mock = new MockAdapter(axios);
-
- store.state.projects[TEST_PROJECT_ID] = {
- branches: {},
- };
- });
-
- afterEach(() => {
- mock.restore();
-
- resetStore(store);
- });
-
- describe('refreshLastCommitData', () => {
- beforeEach(() => {
- store.state.currentProjectId = 'abc/def';
- store.state.currentBranchId = 'master';
- store.state.projects['abc/def'] = {
- id: 4,
- branches: {
- master: {
- commit: null,
- },
- },
- };
- spyOn(service, 'getBranchData').and.returnValue(
- Promise.resolve({
- data: {
- commit: { id: '123' },
- },
- }),
- );
- });
-
- it('calls the service', done => {
- store
- .dispatch('refreshLastCommitData', {
- projectId: store.state.currentProjectId,
- branchId: store.state.currentBranchId,
- })
- .then(() => {
- expect(service.getBranchData).toHaveBeenCalledWith('abc/def', 'master');
-
- done();
- })
- .catch(done.fail);
- });
-
- it('commits getBranchData', done => {
- testAction(
- refreshLastCommitData,
- {
- projectId: store.state.currentProjectId,
- branchId: store.state.currentBranchId,
- },
- store.state,
- // mutations
- [
- {
- type: 'SET_BRANCH_COMMIT',
- payload: {
- projectId: TEST_PROJECT_ID,
- branchId: 'master',
- commit: { id: '123' },
- },
- },
- ],
- // action
- [],
- done,
- );
- });
- });
-
- describe('showBranchNotFoundError', () => {
- it('dispatches setErrorMessage', done => {
- testAction(
- showBranchNotFoundError,
- 'master',
- null,
- [],
- [
- {
- type: 'setErrorMessage',
- payload: {
- text: "Branch <strong>master</strong> was not found in this project's repository.",
- action: jasmine.any(Function),
- actionText: 'Create branch',
- actionPayload: 'master',
- },
- },
- ],
- done,
- );
- });
- });
-
- describe('createNewBranchFromDefault', () => {
- it('calls API', done => {
- spyOn(api, 'createBranch').and.returnValue(Promise.resolve());
- spyOn(router, 'push');
-
- createNewBranchFromDefault(
- {
- state: {
- currentProjectId: 'project-path',
- },
- getters: {
- currentProject: {
- default_branch: 'master',
- },
- },
- dispatch() {},
- },
- 'new-branch-name',
- )
- .then(() => {
- expect(api.createBranch).toHaveBeenCalledWith('project-path', {
- ref: 'master',
- branch: 'new-branch-name',
- });
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('clears error message', done => {
- const dispatchSpy = jasmine.createSpy('dispatch');
- spyOn(api, 'createBranch').and.returnValue(Promise.resolve());
- spyOn(router, 'push');
-
- createNewBranchFromDefault(
- {
- state: {
- currentProjectId: 'project-path',
- },
- getters: {
- currentProject: {
- default_branch: 'master',
- },
- },
- dispatch: dispatchSpy,
- },
- 'new-branch-name',
- )
- .then(() => {
- expect(dispatchSpy).toHaveBeenCalledWith('setErrorMessage', null);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('reloads window', done => {
- spyOn(api, 'createBranch').and.returnValue(Promise.resolve());
- spyOn(router, 'push');
-
- createNewBranchFromDefault(
- {
- state: {
- currentProjectId: 'project-path',
- },
- getters: {
- currentProject: {
- default_branch: 'master',
- },
- },
- dispatch() {},
- },
- 'new-branch-name',
- )
- .then(() => {
- expect(router.push).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('loadEmptyBranch', () => {
- it('creates a blank tree and sets loading state to false', done => {
- testAction(
- loadEmptyBranch,
- { projectId: TEST_PROJECT_ID, branchId: 'master' },
- store.state,
- [
- { type: 'CREATE_TREE', payload: { treePath: `${TEST_PROJECT_ID}/master` } },
- {
- type: 'TOGGLE_LOADING',
- payload: { entry: store.state.trees[`${TEST_PROJECT_ID}/master`], forceValue: false },
- },
- ],
- jasmine.any(Object),
- done,
- );
- });
-
- it('does nothing, if tree already exists', done => {
- const trees = { [`${TEST_PROJECT_ID}/master`]: [] };
-
- testAction(
- loadEmptyBranch,
- { projectId: TEST_PROJECT_ID, branchId: 'master' },
- { trees },
- [],
- [],
- done,
- );
- });
- });
-
- describe('loadFile', () => {
- beforeEach(() => {
- Object.assign(store.state, {
- entries: {
- foo: { pending: false },
- 'foo/bar-pending': { pending: true },
- 'foo/bar': { pending: false },
- },
- });
- spyOn(store, 'dispatch');
- });
-
- it('does nothing, if basePath is not given', () => {
- loadFile(store, { basePath: undefined });
-
- expect(store.dispatch).not.toHaveBeenCalled();
- });
-
- it('handles tree entry action, if basePath is given and the entry is not pending', () => {
- loadFile(store, { basePath: 'foo/bar/' });
-
- expect(store.dispatch).toHaveBeenCalledWith(
- 'handleTreeEntryAction',
- store.state.entries['foo/bar'],
- );
- });
-
- it('does not handle tree entry action, if entry is pending', () => {
- loadFile(store, { basePath: 'foo/bar-pending/' });
-
- expect(store.dispatch).not.toHaveBeenCalledWith('handleTreeEntryAction', jasmine.anything());
- });
-
- it('creates a new temp file supplied via URL if the file does not exist yet', () => {
- loadFile(store, { basePath: 'not-existent.md' });
-
- expect(store.dispatch.calls.count()).toBe(1);
-
- expect(store.dispatch).not.toHaveBeenCalledWith('handleTreeEntryAction', jasmine.anything());
-
- expect(store.dispatch).toHaveBeenCalledWith('createTempEntry', {
- name: 'not-existent.md',
- type: 'blob',
- });
- });
- });
-
- describe('loadBranch', () => {
- const projectId = TEST_PROJECT_ID;
- const branchId = '123-lorem';
- const ref = 'abcd2322';
-
- it('when empty repo, loads empty branch', done => {
- const mockGetters = { emptyRepo: true };
-
- testAction(
- loadBranch,
- { projectId, branchId },
- { ...store.state, ...mockGetters },
- [],
- [{ type: 'loadEmptyBranch', payload: { projectId, branchId } }],
- done,
- );
- });
-
- it('when branch already exists, does nothing', done => {
- store.state.projects[projectId].branches[branchId] = {};
-
- testAction(loadBranch, { projectId, branchId }, store.state, [], [], done);
- });
-
- it('fetches branch data', done => {
- const mockGetters = { findBranch: () => ({ commit: { id: ref } }) };
- spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
-
- loadBranch(
- { getters: mockGetters, state: store.state, dispatch: store.dispatch },
- { projectId, branchId },
- )
- .then(() => {
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['getBranchData', { projectId, branchId }],
- ['getMergeRequestsForBranch', { projectId, branchId }],
- ['getFiles', { projectId, branchId, ref }],
- ]);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('shows an error if branch can not be fetched', done => {
- spyOn(store, 'dispatch').and.returnValue(Promise.reject());
-
- loadBranch(store, { projectId, branchId })
- .then(done.fail)
- .catch(() => {
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['getBranchData', { projectId, branchId }],
- ['showBranchNotFoundError', branchId],
- ]);
- done();
- });
- });
- });
-
- describe('openBranch', () => {
- const projectId = TEST_PROJECT_ID;
- const branchId = '123-lorem';
-
- const branch = {
- projectId,
- branchId,
- };
-
- beforeEach(() => {
- Object.assign(store.state, {
- entries: {
- foo: { pending: false },
- 'foo/bar-pending': { pending: true },
- 'foo/bar': { pending: false },
- },
- });
- });
-
- describe('existing branch', () => {
- beforeEach(() => {
- spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
- });
-
- it('dispatches branch actions', done => {
- openBranch(store, branch)
- .then(() => {
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['setCurrentBranchId', branchId],
- ['loadBranch', { projectId, branchId }],
- ['loadFile', { basePath: undefined }],
- ]);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('non-existent branch', () => {
- beforeEach(() => {
- spyOn(store, 'dispatch').and.returnValue(Promise.reject());
- });
-
- it('dispatches correct branch actions', done => {
- openBranch(store, branch)
- .then(val => {
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['setCurrentBranchId', branchId],
- ['loadBranch', { projectId, branchId }],
- ]);
-
- expect(val).toEqual(
- new Error(
- `An error occurred while getting files for - <strong>${projectId}/${branchId}</strong>`,
- ),
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
-});
diff --git a/spec/javascripts/ide/stores/actions/tree_spec.js b/spec/javascripts/ide/stores/actions/tree_spec.js
deleted file mode 100644
index 2201a3b4b57..00000000000
--- a/spec/javascripts/ide/stores/actions/tree_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testAction from 'spec/helpers/vuex_action_helper';
-import { showTreeEntry, getFiles, setDirectoryData } from '~/ide/stores/actions/tree';
-import * as types from '~/ide/stores/mutation_types';
-import axios from '~/lib/utils/axios_utils';
-import store from '~/ide/stores';
-import service from '~/ide/services';
-import router from '~/ide/ide_router';
-import { file, resetStore, createEntriesFromPaths } from '../../helpers';
-
-describe('Multi-file store tree actions', () => {
- let projectTree;
- let mock;
-
- const basicCallParameters = {
- endpoint: 'rootEndpoint',
- projectId: 'abcproject',
- branch: 'master',
- branchId: 'master',
- ref: '12345678',
- };
-
- beforeEach(() => {
- jasmine.clock().install();
- spyOn(router, 'push');
-
- mock = new MockAdapter(axios);
-
- store.state.currentProjectId = 'abcproject';
- store.state.currentBranchId = 'master';
- store.state.projects.abcproject = {
- web_url: '',
- path_with_namespace: 'foo/abcproject',
- };
- });
-
- afterEach(() => {
- jasmine.clock().uninstall();
- mock.restore();
- resetStore(store);
- });
-
- describe('getFiles', () => {
- describe('success', () => {
- beforeEach(() => {
- spyOn(service, 'getFiles').and.callThrough();
-
- mock
- .onGet(/(.*)/)
- .replyOnce(200, [
- 'file.txt',
- 'folder/fileinfolder.js',
- 'folder/subfolder/fileinsubfolder.js',
- ]);
- });
-
- it('calls service getFiles', done => {
- store
- .dispatch('getFiles', basicCallParameters)
- .then(() => {
- expect(service.getFiles).toHaveBeenCalledWith('foo/abcproject', '12345678');
-
- done();
- })
- .catch(done.fail);
- });
-
- it('adds data into tree', done => {
- store
- .dispatch('getFiles', basicCallParameters)
- .then(() => {
- // The populating of the tree is deferred for performance reasons.
- // See this merge request for details: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/25700
- jasmine.clock().tick(1);
- })
- .then(() => {
- projectTree = store.state.trees['abcproject/master'];
-
- expect(projectTree.tree.length).toBe(2);
- expect(projectTree.tree[0].type).toBe('tree');
- expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js');
- expect(projectTree.tree[1].type).toBe('blob');
- expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob');
- expect(projectTree.tree[0].tree[0].tree[0].name).toBe('fileinsubfolder.js');
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('error', () => {
- it('dispatches error action', done => {
- const dispatch = jasmine.createSpy('dispatchSpy');
-
- store.state.projects = {
- 'abc/def': {
- web_url: `${gl.TEST_HOST}/files`,
- branches: {
- 'master-testing': {
- commit: {
- id: '12345',
- },
- },
- },
- },
- };
- const getters = {
- findBranch: () => store.state.projects['abc/def'].branches['master-testing'],
- };
-
- mock.onGet(/(.*)/).replyOnce(500);
-
- getFiles(
- {
- commit() {},
- dispatch,
- state: store.state,
- getters,
- },
- {
- projectId: 'abc/def',
- branchId: 'master-testing',
- },
- )
- .then(done.fail)
- .catch(() => {
- expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
- text: 'An error occurred while loading all the files.',
- action: jasmine.any(Function),
- actionText: 'Please try again',
- actionPayload: { projectId: 'abc/def', branchId: 'master-testing' },
- });
- done();
- });
- });
- });
- });
-
- describe('toggleTreeOpen', () => {
- let tree;
-
- beforeEach(() => {
- tree = file('testing', '1', 'tree');
- store.state.entries[tree.path] = tree;
- });
-
- it('toggles the tree open', done => {
- store
- .dispatch('toggleTreeOpen', tree.path)
- .then(() => {
- expect(tree.opened).toBeTruthy();
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('showTreeEntry', () => {
- beforeEach(() => {
- const paths = [
- 'grandparent',
- 'ancestor',
- 'grandparent/parent',
- 'grandparent/aunt',
- 'grandparent/parent/child.txt',
- 'grandparent/aunt/cousing.txt',
- ];
-
- Object.assign(store.state.entries, createEntriesFromPaths(paths));
- });
-
- it('opens the parents', done => {
- testAction(
- showTreeEntry,
- 'grandparent/parent/child.txt',
- store.state,
- [{ type: types.SET_TREE_OPEN, payload: 'grandparent/parent' }],
- [{ type: 'showTreeEntry', payload: 'grandparent/parent' }],
- done,
- );
- });
- });
-
- describe('setDirectoryData', () => {
- it('sets tree correctly if there are no opened files yet', done => {
- const treeFile = file({ name: 'README.md' });
- store.state.trees['abcproject/master'] = {};
-
- testAction(
- setDirectoryData,
- { projectId: 'abcproject', branchId: 'master', treeList: [treeFile] },
- store.state,
- [
- {
- type: types.SET_DIRECTORY_DATA,
- payload: {
- treePath: 'abcproject/master',
- data: [treeFile],
- },
- },
- {
- type: types.TOGGLE_LOADING,
- payload: {
- entry: {},
- forceValue: false,
- },
- },
- ],
- [],
- done,
- );
- });
- });
-});
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
deleted file mode 100644
index 364c8421b6b..00000000000
--- a/spec/javascripts/ide/stores/actions_spec.js
+++ /dev/null
@@ -1,1116 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import actions, {
- stageAllChanges,
- unstageAllChanges,
- toggleFileFinder,
- setCurrentBranchId,
- setEmptyStateSvgs,
- updateActivityBarView,
- updateTempFlagForEntry,
- setErrorMessage,
- deleteEntry,
- renameEntry,
- getBranchData,
- createTempEntry,
- discardAllChanges,
-} from '~/ide/stores/actions';
-import axios from '~/lib/utils/axios_utils';
-import { createStore } from '~/ide/stores';
-import * as types from '~/ide/stores/mutation_types';
-import router from '~/ide/ide_router';
-import { file } from '../helpers';
-import testAction from '../../helpers/vuex_action_helper';
-import eventHub from '~/ide/eventhub';
-
-describe('Multi-file store actions', () => {
- let store;
-
- beforeEach(() => {
- store = createStore();
-
- spyOn(store, 'commit').and.callThrough();
- spyOn(store, 'dispatch').and.callThrough();
- spyOn(router, 'push');
- });
-
- describe('redirectToUrl', () => {
- it('calls visitUrl', done => {
- const visitUrl = spyOnDependency(actions, 'visitUrl');
-
- store
- .dispatch('redirectToUrl', 'test')
- .then(() => {
- expect(visitUrl).toHaveBeenCalledWith('test');
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('setInitialData', () => {
- it('commits initial data', done => {
- store
- .dispatch('setInitialData', { canCommit: true })
- .then(() => {
- expect(store.state.canCommit).toBeTruthy();
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('discardAllChanges', () => {
- const paths = ['to_discard', 'another_one_to_discard'];
-
- beforeEach(() => {
- paths.forEach(path => {
- const f = file(path);
- f.changed = true;
-
- store.state.openFiles.push(f);
- store.state.changedFiles.push(f);
- store.state.entries[f.path] = f;
- });
- });
-
- it('discards all changes in file', () => {
- const expectedCalls = paths.map(path => ['restoreOriginalFile', path]);
-
- discardAllChanges(store);
-
- expect(store.dispatch.calls.allArgs()).toEqual(jasmine.arrayContaining(expectedCalls));
- });
-
- it('removes all files from changedFiles state', done => {
- store
- .dispatch('discardAllChanges')
- .then(() => {
- expect(store.state.changedFiles.length).toBe(0);
- expect(store.state.openFiles.length).toBe(2);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('closeAllFiles', () => {
- beforeEach(() => {
- const f = file('closeAll');
- store.state.openFiles.push(f);
- store.state.openFiles[0].opened = true;
- store.state.entries[f.path] = f;
- });
-
- it('closes all open files', done => {
- store
- .dispatch('closeAllFiles')
- .then(() => {
- expect(store.state.openFiles.length).toBe(0);
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('createTempEntry', () => {
- beforeEach(() => {
- document.body.innerHTML += '<div class="flash-container"></div>';
-
- store.state.currentProjectId = 'abcproject';
- store.state.currentBranchId = 'mybranch';
-
- store.state.trees['abcproject/mybranch'] = {
- tree: [],
- };
- store.state.projects.abcproject = {
- web_url: '',
- };
- });
-
- afterEach(() => {
- document.querySelector('.flash-container').remove();
- });
-
- describe('tree', () => {
- it('creates temp tree', done => {
- store
- .dispatch('createTempEntry', {
- branchId: store.state.currentBranchId,
- name: 'test',
- type: 'tree',
- })
- .then(() => {
- const entry = store.state.entries.test;
-
- expect(entry).not.toBeNull();
- expect(entry.type).toBe('tree');
-
- done();
- })
- .catch(done.fail);
- });
-
- it('creates new folder inside another tree', done => {
- const tree = {
- type: 'tree',
- name: 'testing',
- path: 'testing',
- tree: [],
- };
-
- store.state.entries[tree.path] = tree;
-
- store
- .dispatch('createTempEntry', {
- branchId: store.state.currentBranchId,
- name: 'testing/test',
- type: 'tree',
- })
- .then(() => {
- expect(tree.tree[0].tempFile).toBeTruthy();
- expect(tree.tree[0].name).toBe('test');
- expect(tree.tree[0].type).toBe('tree');
-
- done();
- })
- .catch(done.fail);
- });
-
- it('does not create new tree if already exists', done => {
- const tree = {
- type: 'tree',
- path: 'testing',
- tempFile: false,
- tree: [],
- };
-
- store.state.entries[tree.path] = tree;
-
- store
- .dispatch('createTempEntry', {
- branchId: store.state.currentBranchId,
- name: 'testing',
- type: 'tree',
- })
- .then(() => {
- expect(store.state.entries[tree.path].tempFile).toEqual(false);
- expect(document.querySelector('.flash-alert')).not.toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('blob', () => {
- it('creates temp file', done => {
- const name = 'test';
-
- store
- .dispatch('createTempEntry', {
- name,
- branchId: 'mybranch',
- type: 'blob',
- })
- .then(() => {
- const f = store.state.entries[name];
-
- expect(f.tempFile).toBeTruthy();
- expect(store.state.trees['abcproject/mybranch'].tree.length).toBe(1);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('adds tmp file to open files', done => {
- const name = 'test';
-
- store
- .dispatch('createTempEntry', {
- name,
- branchId: 'mybranch',
- type: 'blob',
- })
- .then(() => {
- const f = store.state.entries[name];
-
- expect(store.state.openFiles.length).toBe(1);
- expect(store.state.openFiles[0].name).toBe(f.name);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('adds tmp file to staged files', done => {
- const name = 'test';
-
- store
- .dispatch('createTempEntry', {
- name,
- branchId: 'mybranch',
- type: 'blob',
- })
- .then(() => {
- expect(store.state.stagedFiles).toEqual([jasmine.objectContaining({ name })]);
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets tmp file as active', () => {
- createTempEntry(store, { name: 'test', branchId: 'mybranch', type: 'blob' });
-
- expect(store.dispatch).toHaveBeenCalledWith('setFileActive', 'test');
- });
-
- it('creates flash message if file already exists', done => {
- const f = file('test', '1', 'blob');
- store.state.trees['abcproject/mybranch'].tree = [f];
- store.state.entries[f.path] = f;
-
- store
- .dispatch('createTempEntry', {
- name: 'test',
- branchId: 'mybranch',
- type: 'blob',
- })
- .then(() => {
- expect(document.querySelector('.flash-alert')?.textContent.trim()).toEqual(
- `The name "${f.name}" is already taken in this directory.`,
- );
-
- done();
- })
- .catch(done.fail);
- });
-
- it('bursts unused seal', done => {
- store
- .dispatch('createTempEntry', {
- name: 'test',
- branchId: 'mybranch',
- type: 'blob',
- })
- .then(() => {
- expect(store.state.unusedSeal).toBe(false);
-
- done();
- })
- .catch(done.fail);
- });
- });
- });
-
- describe('scrollToTab', () => {
- it('focuses the current active element', done => {
- document.body.innerHTML +=
- '<div id="tabs"><div class="active"><div class="repo-tab"></div></div></div>';
- const el = document.querySelector('.repo-tab');
- spyOn(el, 'focus');
-
- store
- .dispatch('scrollToTab')
- .then(() => {
- setTimeout(() => {
- expect(el.focus).toHaveBeenCalled();
-
- document.getElementById('tabs').remove();
-
- done();
- });
- })
- .catch(done.fail);
- });
- });
-
- describe('stage/unstageAllChanges', () => {
- let file1;
- let file2;
-
- beforeEach(() => {
- file1 = { ...file('test'), content: 'changed test', raw: 'test' };
- file2 = { ...file('test2'), content: 'changed test2', raw: 'test2' };
-
- store.state.openFiles = [file1];
- store.state.changedFiles = [file1];
- store.state.stagedFiles = [{ ...file2, content: 'staged test' }];
-
- store.state.entries = {
- [file1.path]: { ...file1 },
- [file2.path]: { ...file2 },
- };
- });
-
- describe('stageAllChanges', () => {
- it('adds all files from changedFiles to stagedFiles', () => {
- stageAllChanges(store);
-
- expect(store.commit.calls.allArgs()).toEqual([
- [types.SET_LAST_COMMIT_MSG, ''],
- [types.STAGE_CHANGE, jasmine.objectContaining({ path: file1.path })],
- ]);
- });
-
- it('opens pending tab if a change exists in that file', () => {
- stageAllChanges(store);
-
- expect(store.dispatch.calls.allArgs()).toEqual([
- [
- 'openPendingTab',
- { file: { ...file1, staged: true, changed: true }, keyPrefix: 'staged' },
- ],
- ]);
- });
-
- it('does not open pending tab if no change exists in that file', () => {
- store.state.entries[file1.path].content = 'test';
- store.state.stagedFiles = [file1];
- store.state.changedFiles = [store.state.entries[file1.path]];
-
- stageAllChanges(store);
-
- expect(store.dispatch).not.toHaveBeenCalled();
- });
- });
-
- describe('unstageAllChanges', () => {
- it('removes all files from stagedFiles after unstaging', () => {
- unstageAllChanges(store);
-
- expect(store.commit.calls.allArgs()).toEqual([
- [types.UNSTAGE_CHANGE, jasmine.objectContaining({ path: file2.path })],
- ]);
- });
-
- it('opens pending tab if a change exists in that file', () => {
- unstageAllChanges(store);
-
- expect(store.dispatch.calls.allArgs()).toEqual([
- ['openPendingTab', { file: file1, keyPrefix: 'unstaged' }],
- ]);
- });
-
- it('does not open pending tab if no change exists in that file', () => {
- store.state.entries[file1.path].content = 'test';
- store.state.stagedFiles = [file1];
- store.state.changedFiles = [store.state.entries[file1.path]];
-
- unstageAllChanges(store);
-
- expect(store.dispatch).not.toHaveBeenCalled();
- });
- });
- });
-
- describe('updateViewer', () => {
- it('updates viewer state', done => {
- store
- .dispatch('updateViewer', 'diff')
- .then(() => {
- expect(store.state.viewer).toBe('diff');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('updateActivityBarView', () => {
- it('commits UPDATE_ACTIVITY_BAR_VIEW', done => {
- testAction(
- updateActivityBarView,
- 'test',
- {},
- [{ type: 'UPDATE_ACTIVITY_BAR_VIEW', payload: 'test' }],
- [],
- done,
- );
- });
- });
-
- describe('setEmptyStateSvgs', () => {
- it('commits setEmptyStateSvgs', done => {
- testAction(
- setEmptyStateSvgs,
- 'svg',
- {},
- [{ type: 'SET_EMPTY_STATE_SVGS', payload: 'svg' }],
- [],
- done,
- );
- });
- });
-
- describe('updateTempFlagForEntry', () => {
- it('commits UPDATE_TEMP_FLAG', done => {
- const f = {
- ...file(),
- path: 'test',
- tempFile: true,
- };
- store.state.entries[f.path] = f;
-
- testAction(
- updateTempFlagForEntry,
- { file: f, tempFile: false },
- store.state,
- [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
- [],
- done,
- );
- });
-
- it('commits UPDATE_TEMP_FLAG and dispatches for parent', done => {
- const parent = {
- ...file(),
- path: 'testing',
- };
- const f = {
- ...file(),
- path: 'test',
- parentPath: 'testing',
- };
- store.state.entries[parent.path] = parent;
- store.state.entries[f.path] = f;
-
- testAction(
- updateTempFlagForEntry,
- { file: f, tempFile: false },
- store.state,
- [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
- [{ type: 'updateTempFlagForEntry', payload: { file: parent, tempFile: false } }],
- done,
- );
- });
-
- it('does not dispatch for parent, if parent does not exist', done => {
- const f = {
- ...file(),
- path: 'test',
- parentPath: 'testing',
- };
- store.state.entries[f.path] = f;
-
- testAction(
- updateTempFlagForEntry,
- { file: f, tempFile: false },
- store.state,
- [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
- [],
- done,
- );
- });
- });
-
- describe('setCurrentBranchId', () => {
- it('commits setCurrentBranchId', done => {
- testAction(
- setCurrentBranchId,
- 'branchId',
- {},
- [{ type: 'SET_CURRENT_BRANCH', payload: 'branchId' }],
- [],
- done,
- );
- });
- });
-
- describe('toggleFileFinder', () => {
- it('commits TOGGLE_FILE_FINDER', done => {
- testAction(
- toggleFileFinder,
- true,
- null,
- [{ type: 'TOGGLE_FILE_FINDER', payload: true }],
- [],
- done,
- );
- });
- });
-
- describe('setErrorMessage', () => {
- it('commis error messsage', done => {
- testAction(
- setErrorMessage,
- 'error',
- null,
- [{ type: types.SET_ERROR_MESSAGE, payload: 'error' }],
- [],
- done,
- );
- });
- });
-
- describe('deleteEntry', () => {
- it('commits entry deletion', done => {
- store.state.entries.path = 'testing';
-
- testAction(
- deleteEntry,
- 'path',
- store.state,
- [{ type: types.DELETE_ENTRY, payload: 'path' }],
- [{ type: 'stageChange', payload: 'path' }, { type: 'triggerFilesChange' }],
- done,
- );
- });
-
- it('does not delete a folder after it is emptied', done => {
- const testFolder = {
- type: 'tree',
- tree: [],
- };
- const testEntry = {
- path: 'testFolder/entry-to-delete',
- parentPath: 'testFolder',
- opened: false,
- tree: [],
- };
- testFolder.tree.push(testEntry);
- store.state.entries = {
- testFolder,
- 'testFolder/entry-to-delete': testEntry,
- };
-
- testAction(
- deleteEntry,
- 'testFolder/entry-to-delete',
- store.state,
- [{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
- [
- { type: 'stageChange', payload: 'testFolder/entry-to-delete' },
- { type: 'triggerFilesChange' },
- ],
- done,
- );
- });
-
- describe('when renamed', () => {
- let testEntry;
-
- beforeEach(() => {
- testEntry = {
- path: 'test',
- name: 'test',
- prevPath: 'test_old',
- prevName: 'test_old',
- prevParentPath: '',
- };
-
- store.state.entries = { test: testEntry };
- });
-
- describe('and previous does not exist', () => {
- it('reverts the rename before deleting', done => {
- testAction(
- deleteEntry,
- testEntry.path,
- store.state,
- [],
- [
- {
- type: 'renameEntry',
- payload: {
- path: testEntry.path,
- name: testEntry.prevName,
- parentPath: testEntry.prevParentPath,
- },
- },
- {
- type: 'deleteEntry',
- payload: testEntry.prevPath,
- },
- ],
- done,
- );
- });
- });
-
- describe('and previous exists', () => {
- beforeEach(() => {
- const oldEntry = {
- path: testEntry.prevPath,
- name: testEntry.prevName,
- };
-
- store.state.entries[oldEntry.path] = oldEntry;
- });
-
- it('does not revert rename before deleting', done => {
- testAction(
- deleteEntry,
- testEntry.path,
- store.state,
- [{ type: types.DELETE_ENTRY, payload: testEntry.path }],
- [{ type: 'stageChange', payload: testEntry.path }, { type: 'triggerFilesChange' }],
- done,
- );
- });
-
- it('when previous is deleted, it reverts rename before deleting', done => {
- store.state.entries[testEntry.prevPath].deleted = true;
-
- testAction(
- deleteEntry,
- testEntry.path,
- store.state,
- [],
- [
- {
- type: 'renameEntry',
- payload: {
- path: testEntry.path,
- name: testEntry.prevName,
- parentPath: testEntry.prevParentPath,
- },
- },
- {
- type: 'deleteEntry',
- payload: testEntry.prevPath,
- },
- ],
- done,
- );
- });
- });
- });
-
- it('bursts unused seal', done => {
- store.state.entries.test = file('test');
-
- store
- .dispatch('deleteEntry', 'test')
- .then(() => {
- expect(store.state.unusedSeal).toBe(false);
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('renameEntry', () => {
- describe('purging of file model cache', () => {
- beforeEach(() => {
- spyOn(eventHub, '$emit');
- });
-
- it('does not purge model cache for temporary entries that got renamed', done => {
- Object.assign(store.state.entries, {
- test: {
- ...file('test'),
- key: 'foo-key',
- type: 'blob',
- tempFile: true,
- },
- });
-
- store
- .dispatch('renameEntry', {
- path: 'test',
- name: 'new',
- })
- .then(() => {
- expect(eventHub.$emit.calls.allArgs()).not.toContain(
- 'editor.update.model.dispose.foo-bar',
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('purges model cache for renamed entry', done => {
- Object.assign(store.state.entries, {
- test: {
- ...file('test'),
- key: 'foo-key',
- type: 'blob',
- tempFile: false,
- },
- });
-
- store
- .dispatch('renameEntry', {
- path: 'test',
- name: 'new',
- })
- .then(() => {
- expect(eventHub.$emit).toHaveBeenCalled();
- expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.dispose.foo-key`);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('single entry', () => {
- let origEntry;
- let renamedEntry;
-
- beforeEach(() => {
- // Need to insert both because `testAction` doesn't actually call the mutation
- origEntry = file('orig', 'orig', 'blob');
- renamedEntry = {
- ...file('renamed', 'renamed', 'blob'),
- prevKey: origEntry.key,
- prevName: origEntry.name,
- prevPath: origEntry.path,
- };
-
- Object.assign(store.state.entries, {
- orig: origEntry,
- renamed: renamedEntry,
- });
- });
-
- it('by default renames an entry and stages it', () => {
- const dispatch = jasmine.createSpy();
- const commit = jasmine.createSpy();
-
- renameEntry(
- { dispatch, commit, state: store.state, getters: store.getters },
- { path: 'orig', name: 'renamed' },
- );
-
- expect(commit.calls.allArgs()).toEqual([
- [types.RENAME_ENTRY, { path: 'orig', name: 'renamed', parentPath: undefined }],
- [types.STAGE_CHANGE, jasmine.objectContaining({ path: 'renamed' })],
- ]);
- });
-
- it('if not changed, completely unstages and discards entry if renamed to original', done => {
- testAction(
- renameEntry,
- { path: 'renamed', name: 'orig' },
- store.state,
- [
- {
- type: types.RENAME_ENTRY,
- payload: {
- path: 'renamed',
- name: 'orig',
- parentPath: undefined,
- },
- },
- {
- type: types.REMOVE_FILE_FROM_STAGED_AND_CHANGED,
- payload: origEntry,
- },
- ],
- [{ type: 'triggerFilesChange' }],
- done,
- );
- });
-
- it('if already in changed, does not add to change', done => {
- store.state.changedFiles.push(renamedEntry);
-
- testAction(
- renameEntry,
- { path: 'orig', name: 'renamed' },
- store.state,
- [jasmine.objectContaining({ type: types.RENAME_ENTRY })],
- [{ type: 'triggerFilesChange' }],
- done,
- );
- });
-
- it('routes to the renamed file if the original file has been opened', done => {
- Object.assign(store.state.entries.orig, {
- opened: true,
- url: '/foo-bar.md',
- });
-
- store
- .dispatch('renameEntry', {
- path: 'orig',
- name: 'renamed',
- })
- .then(() => {
- expect(router.push.calls.count()).toBe(1);
- expect(router.push).toHaveBeenCalledWith(`/project/foo-bar.md`);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('bursts unused seal', done => {
- store
- .dispatch('renameEntry', {
- path: 'orig',
- name: 'renamed',
- })
- .then(() => {
- expect(store.state.unusedSeal).toBe(false);
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('folder', () => {
- let folder;
- let file1;
- let file2;
-
- beforeEach(() => {
- folder = file('folder', 'folder', 'tree');
- file1 = file('file-1', 'file-1', 'blob', folder);
- file2 = file('file-2', 'file-2', 'blob', folder);
-
- folder.tree = [file1, file2];
-
- Object.assign(store.state.entries, {
- [folder.path]: folder,
- [file1.path]: file1,
- [file2.path]: file2,
- });
- });
-
- it('updates entries in a folder correctly, when folder is renamed', done => {
- store
- .dispatch('renameEntry', {
- path: 'folder',
- name: 'new-folder',
- })
- .then(() => {
- const keys = Object.keys(store.state.entries);
-
- expect(keys.length).toBe(3);
- expect(keys.indexOf('new-folder')).toBe(0);
- expect(keys.indexOf('new-folder/file-1')).toBe(1);
- expect(keys.indexOf('new-folder/file-2')).toBe(2);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('discards renaming of an entry if the root folder is renamed back to a previous name', done => {
- const rootFolder = file('old-folder', 'old-folder', 'tree');
- const testEntry = file('test', 'test', 'blob', rootFolder);
-
- Object.assign(store.state, {
- entries: {
- 'old-folder': {
- ...rootFolder,
- tree: [testEntry],
- },
- 'old-folder/test': testEntry,
- },
- });
-
- store
- .dispatch('renameEntry', {
- path: 'old-folder',
- name: 'new-folder',
- })
- .then(() => {
- const { entries } = store.state;
-
- expect(Object.keys(entries).length).toBe(2);
- expect(entries['old-folder']).toBeUndefined();
- expect(entries['old-folder/test']).toBeUndefined();
-
- expect(entries['new-folder']).toBeDefined();
- expect(entries['new-folder/test']).toEqual(
- jasmine.objectContaining({
- path: 'new-folder/test',
- name: 'test',
- prevPath: 'old-folder/test',
- prevName: 'test',
- }),
- );
- })
- .then(() =>
- store.dispatch('renameEntry', {
- path: 'new-folder',
- name: 'old-folder',
- }),
- )
- .then(() => {
- const { entries } = store.state;
-
- expect(Object.keys(entries).length).toBe(2);
- expect(entries['new-folder']).toBeUndefined();
- expect(entries['new-folder/test']).toBeUndefined();
-
- expect(entries['old-folder']).toBeDefined();
- expect(entries['old-folder/test']).toEqual(
- jasmine.objectContaining({
- path: 'old-folder/test',
- name: 'test',
- prevPath: undefined,
- prevName: undefined,
- }),
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- describe('with file in directory', () => {
- const parentPath = 'original-dir';
- const newParentPath = 'new-dir';
- const fileName = 'test.md';
- const filePath = `${parentPath}/${fileName}`;
-
- let rootDir;
-
- beforeEach(() => {
- const parentEntry = file(parentPath, parentPath, 'tree');
- const fileEntry = file(filePath, filePath, 'blob', parentEntry);
- rootDir = {
- tree: [],
- };
-
- Object.assign(store.state, {
- entries: {
- [parentPath]: {
- ...parentEntry,
- tree: [fileEntry],
- },
- [filePath]: fileEntry,
- },
- trees: {
- '/': rootDir,
- },
- });
- });
-
- it('creates new directory', done => {
- expect(store.state.entries[newParentPath]).toBeUndefined();
-
- store
- .dispatch('renameEntry', { path: filePath, name: fileName, parentPath: newParentPath })
- .then(() => {
- expect(store.state.entries[newParentPath]).toEqual(
- jasmine.objectContaining({
- path: newParentPath,
- type: 'tree',
- tree: jasmine.arrayContaining([
- store.state.entries[`${newParentPath}/${fileName}`],
- ]),
- }),
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- describe('when new directory exists', () => {
- let newDir;
-
- beforeEach(() => {
- newDir = file(newParentPath, newParentPath, 'tree');
-
- store.state.entries[newDir.path] = newDir;
- rootDir.tree.push(newDir);
- });
-
- it('inserts in new directory', done => {
- expect(newDir.tree).toEqual([]);
-
- store
- .dispatch('renameEntry', {
- path: filePath,
- name: fileName,
- parentPath: newParentPath,
- })
- .then(() => {
- expect(newDir.tree).toEqual([store.state.entries[`${newParentPath}/${fileName}`]]);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('when new directory is deleted, it undeletes it', done => {
- store.dispatch('deleteEntry', newParentPath);
-
- expect(store.state.entries[newParentPath].deleted).toBe(true);
- expect(rootDir.tree.some(x => x.path === newParentPath)).toBe(false);
-
- store
- .dispatch('renameEntry', {
- path: filePath,
- name: fileName,
- parentPath: newParentPath,
- })
- .then(() => {
- expect(store.state.entries[newParentPath].deleted).toBe(false);
- expect(rootDir.tree.some(x => x.path === newParentPath)).toBe(true);
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
- });
- });
-
- describe('getBranchData', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('error', () => {
- let dispatch;
- let callParams;
-
- beforeEach(() => {
- callParams = [
- {
- commit() {},
- state: store.state,
- },
- {
- projectId: 'abc/def',
- branchId: 'master-testing',
- },
- ];
- dispatch = jasmine.createSpy('dispatchSpy');
- document.body.innerHTML += '<div class="flash-container"></div>';
- });
-
- afterEach(() => {
- document.querySelector('.flash-container').remove();
- });
-
- it('passes the error further unchanged without dispatching any action when response is 404', done => {
- mock.onGet(/(.*)/).replyOnce(404);
-
- getBranchData(...callParams)
- .then(done.fail)
- .catch(e => {
- expect(dispatch.calls.count()).toEqual(0);
- expect(e.response.status).toEqual(404);
- expect(document.querySelector('.flash-alert')).toBeNull();
- done();
- });
- });
-
- it('does not pass the error further and flashes an alert if error is not 404', done => {
- mock.onGet(/(.*)/).replyOnce(418);
-
- getBranchData(...callParams)
- .then(done.fail)
- .catch(e => {
- expect(dispatch.calls.count()).toEqual(0);
- expect(e.response).toBeUndefined();
- expect(document.querySelector('.flash-alert')).not.toBeNull();
- done();
- });
- });
- });
- });
-});
diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
deleted file mode 100644
index fb8cb300209..00000000000
--- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js
+++ /dev/null
@@ -1,603 +0,0 @@
-import { resetStore, file } from 'spec/ide/helpers';
-import rootActions from '~/ide/stores/actions';
-import { createStore } from '~/ide/stores';
-import service from '~/ide/services';
-import router from '~/ide/ide_router';
-import eventHub from '~/ide/eventhub';
-import consts from '~/ide/stores/modules/commit/constants';
-import * as mutationTypes from '~/ide/stores/modules/commit/mutation_types';
-import * as actions from '~/ide/stores/modules/commit/actions';
-import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
-import testAction from '../../../../helpers/vuex_action_helper';
-
-const TEST_COMMIT_SHA = '123456789';
-const store = createStore();
-
-describe('IDE commit module actions', () => {
- beforeEach(() => {
- spyOn(router, 'push');
- });
-
- afterEach(() => {
- resetStore(store);
- });
-
- describe('updateCommitMessage', () => {
- it('updates store with new commit message', done => {
- store
- .dispatch('commit/updateCommitMessage', 'testing')
- .then(() => {
- expect(store.state.commit.commitMessage).toBe('testing');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('discardDraft', () => {
- it('resets commit message to blank', done => {
- store.state.commit.commitMessage = 'testing';
-
- store
- .dispatch('commit/discardDraft')
- .then(() => {
- expect(store.state.commit.commitMessage).not.toBe('testing');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('updateCommitAction', () => {
- it('updates store with new commit action', done => {
- store
- .dispatch('commit/updateCommitAction', '1')
- .then(() => {
- expect(store.state.commit.commitAction).toBe('1');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('sets shouldCreateMR to true if "Create new MR" option is visible', done => {
- Object.assign(store.state, {
- shouldHideNewMrOption: false,
- });
-
- testAction(
- actions.updateCommitAction,
- {},
- store.state,
- [
- {
- type: mutationTypes.UPDATE_COMMIT_ACTION,
- payload: { commitAction: jasmine.anything() },
- },
- { type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: true },
- ],
- [],
- done,
- );
- });
-
- it('sets shouldCreateMR to false if "Create new MR" option is hidden', done => {
- Object.assign(store.state, {
- shouldHideNewMrOption: true,
- });
-
- testAction(
- actions.updateCommitAction,
- {},
- store.state,
- [
- {
- type: mutationTypes.UPDATE_COMMIT_ACTION,
- payload: { commitAction: jasmine.anything() },
- },
- { type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: false },
- ],
- [],
- done,
- );
- });
- });
-
- describe('updateBranchName', () => {
- it('updates store with new branch name', done => {
- store
- .dispatch('commit/updateBranchName', 'branch-name')
- .then(() => {
- expect(store.state.commit.newBranchName).toBe('branch-name');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('setLastCommitMessage', () => {
- beforeEach(() => {
- Object.assign(store.state, {
- currentProjectId: 'abcproject',
- projects: {
- abcproject: {
- web_url: 'http://testing',
- },
- },
- });
- });
-
- it('updates commit message with short_id', done => {
- store
- .dispatch('commit/setLastCommitMessage', { short_id: '123' })
- .then(() => {
- expect(store.state.lastCommitMsg).toContain(
- 'Your changes have been committed. Commit <a href="http://testing/-/commit/123" class="commit-sha">123</a>',
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('updates commit message with stats', done => {
- store
- .dispatch('commit/setLastCommitMessage', {
- short_id: '123',
- stats: {
- additions: '1',
- deletions: '2',
- },
- })
- .then(() => {
- expect(store.state.lastCommitMsg).toBe(
- 'Your changes have been committed. Commit <a href="http://testing/-/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.',
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('updateFilesAfterCommit', () => {
- const data = {
- id: '123',
- message: 'testing commit message',
- committed_date: '123',
- committer_name: 'root',
- };
- const branch = 'master';
- let f;
-
- beforeEach(() => {
- spyOn(eventHub, '$emit');
-
- f = file('changedFile');
- Object.assign(f, {
- active: true,
- changed: true,
- content: 'file content',
- });
-
- Object.assign(store.state, {
- currentProjectId: 'abcproject',
- currentBranchId: 'master',
- projects: {
- abcproject: {
- web_url: 'web_url',
- branches: {
- master: {
- workingReference: '',
- commit: {
- short_id: TEST_COMMIT_SHA,
- },
- },
- },
- },
- },
- stagedFiles: [
- f,
- {
- ...file('changedFile2'),
- changed: true,
- },
- ],
- openFiles: store.state.stagedFiles,
- });
-
- store.state.stagedFiles.forEach(stagedFile => {
- store.state.entries[stagedFile.path] = stagedFile;
- });
- });
-
- it('updates stores working reference', done => {
- store
- .dispatch('commit/updateFilesAfterCommit', {
- data,
- branch,
- })
- .then(() => {
- expect(store.state.projects.abcproject.branches.master.workingReference).toBe(data.id);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('resets all files changed status', done => {
- store
- .dispatch('commit/updateFilesAfterCommit', {
- data,
- branch,
- })
- .then(() => {
- store.state.openFiles.forEach(entry => {
- expect(entry.changed).toBeFalsy();
- });
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('sets files commit data', done => {
- store
- .dispatch('commit/updateFilesAfterCommit', {
- data,
- branch,
- })
- .then(() => {
- expect(f.lastCommitSha).toBe(data.id);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('updates raw content for changed file', done => {
- store
- .dispatch('commit/updateFilesAfterCommit', {
- data,
- branch,
- })
- .then(() => {
- expect(f.raw).toBe(f.content);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('emits changed event for file', done => {
- store
- .dispatch('commit/updateFilesAfterCommit', {
- data,
- branch,
- })
- .then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.content.${f.key}`, {
- content: f.content,
- changed: false,
- });
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('commitChanges', () => {
- let visitUrl;
-
- beforeEach(() => {
- visitUrl = spyOnDependency(rootActions, 'visitUrl');
-
- document.body.innerHTML += '<div class="flash-container"></div>';
-
- const f = {
- ...file('changed'),
- type: 'blob',
- active: true,
- lastCommitSha: TEST_COMMIT_SHA,
- content: '\n',
- raw: '\n',
- };
-
- Object.assign(store.state, {
- stagedFiles: [f],
- changedFiles: [f],
- openFiles: [f],
- currentProjectId: 'abcproject',
- currentBranchId: 'master',
- projects: {
- abcproject: {
- web_url: 'webUrl',
- branches: {
- master: {
- workingReference: '1',
- commit: {
- id: TEST_COMMIT_SHA,
- },
- },
- },
- userPermissions: {
- [PERMISSION_CREATE_MR]: true,
- },
- },
- },
- });
-
- store.state.commit.commitAction = '2';
- store.state.commit.commitMessage = 'testing 123';
-
- store.state.openFiles.forEach(localF => {
- store.state.entries[localF.path] = localF;
- });
- });
-
- afterEach(() => {
- document.querySelector('.flash-container').remove();
- });
-
- describe('success', () => {
- const COMMIT_RESPONSE = {
- id: '123456',
- short_id: '123',
- message: 'test message',
- committed_date: 'date',
- parent_ids: '321',
- stats: {
- additions: '1',
- deletions: '2',
- },
- };
-
- beforeEach(() => {
- spyOn(service, 'commit').and.returnValue(
- Promise.resolve({
- data: COMMIT_RESPONSE,
- }),
- );
- });
-
- it('calls service', done => {
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(service.commit).toHaveBeenCalledWith('abcproject', {
- branch: jasmine.anything(),
- commit_message: 'testing 123',
- actions: [
- {
- action: commitActionTypes.update,
- file_path: jasmine.anything(),
- content: '\n',
- encoding: jasmine.anything(),
- last_commit_id: undefined,
- previous_path: undefined,
- },
- ],
- start_sha: TEST_COMMIT_SHA,
- });
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sends lastCommit ID when not creating new branch', done => {
- store.state.commit.commitAction = '1';
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(service.commit).toHaveBeenCalledWith('abcproject', {
- branch: jasmine.anything(),
- commit_message: 'testing 123',
- actions: [
- {
- action: commitActionTypes.update,
- file_path: jasmine.anything(),
- content: '\n',
- encoding: jasmine.anything(),
- last_commit_id: TEST_COMMIT_SHA,
- previous_path: undefined,
- },
- ],
- start_sha: undefined,
- });
-
- done();
- })
- .catch(done.fail);
- });
-
- it('sets last Commit Msg', done => {
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.state.lastCommitMsg).toBe(
- 'Your changes have been committed. Commit <a href="webUrl/-/commit/123" class="commit-sha">123</a> with 1 additions, 2 deletions.',
- );
-
- done();
- })
- .catch(done.fail);
- });
-
- it('adds commit data to files', done => {
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.state.entries[store.state.openFiles[0].path].lastCommitSha).toBe(
- COMMIT_RESPONSE.id,
- );
-
- done();
- })
- .catch(done.fail);
- });
-
- it('resets stores commit actions', done => {
- store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH;
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.state.commit.commitAction).not.toBe(consts.COMMIT_TO_NEW_BRANCH);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('removes all staged files', done => {
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.state.stagedFiles.length).toBe(0);
- })
- .then(done)
- .catch(done.fail);
- });
-
- describe('merge request', () => {
- it('redirects to new merge request page', done => {
- spyOn(eventHub, '$on');
-
- store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH;
- store.state.commit.shouldCreateMR = true;
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(visitUrl).toHaveBeenCalledWith(
- `webUrl/-/merge_requests/new?merge_request[source_branch]=${
- store.getters['commit/placeholderBranchName']
- }&merge_request[target_branch]=master&nav_source=webide`,
- );
-
- done();
- })
- .catch(done.fail);
- });
-
- it('does not redirect to new merge request page when shouldCreateMR is not checked', done => {
- spyOn(eventHub, '$on');
-
- store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH;
- store.state.commit.shouldCreateMR = false;
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(visitUrl).not.toHaveBeenCalled();
- done();
- })
- .catch(done.fail);
- });
-
- it('resets changed files before redirecting', done => {
- visitUrl = visitUrl.and.callFake(() => {
- expect(store.state.stagedFiles.length).toBe(0);
- done();
- });
-
- spyOn(eventHub, '$on');
-
- store.state.commit.commitAction = '3';
-
- store.dispatch('commit/commitChanges').catch(done.fail);
- });
- });
- });
-
- describe('failed', () => {
- beforeEach(() => {
- spyOn(service, 'commit').and.returnValue(
- Promise.resolve({
- data: {
- message: 'failed message',
- },
- }),
- );
- });
-
- it('shows failed message', done => {
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- const alert = document.querySelector('.flash-container');
-
- expect(alert.textContent.trim()).toBe('failed message');
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('first commit of a branch', () => {
- const COMMIT_RESPONSE = {
- id: '123456',
- short_id: '123',
- message: 'test message',
- committed_date: 'date',
- parent_ids: [],
- stats: {
- additions: '1',
- deletions: '2',
- },
- };
-
- it('commits TOGGLE_EMPTY_STATE mutation on empty repo', done => {
- spyOn(service, 'commit').and.returnValue(
- Promise.resolve({
- data: COMMIT_RESPONSE,
- }),
- );
-
- spyOn(store, 'commit').and.callThrough();
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.commit.calls.allArgs()).toEqual(
- jasmine.arrayContaining([
- ['TOGGLE_EMPTY_STATE', jasmine.any(Object), jasmine.any(Object)],
- ]),
- );
- done();
- })
- .catch(done.fail);
- });
-
- it('does not commmit TOGGLE_EMPTY_STATE mutation on existing project', done => {
- COMMIT_RESPONSE.parent_ids.push('1234');
- spyOn(service, 'commit').and.returnValue(
- Promise.resolve({
- data: COMMIT_RESPONSE,
- }),
- );
- spyOn(store, 'commit').and.callThrough();
-
- store
- .dispatch('commit/commitChanges')
- .then(() => {
- expect(store.commit.calls.allArgs()).not.toEqual(
- jasmine.arrayContaining([
- ['TOGGLE_EMPTY_STATE', jasmine.any(Object), jasmine.any(Object)],
- ]),
- );
- done();
- })
- .catch(done.fail);
- });
- });
- });
-
- describe('toggleShouldCreateMR', () => {
- it('commits both toggle and interacting with MR checkbox actions', done => {
- testAction(
- actions.toggleShouldCreateMR,
- {},
- store.state,
- [{ type: mutationTypes.TOGGLE_SHOULD_CREATE_MR }],
- [],
- done,
- );
- });
- });
-});
diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js
deleted file mode 100644
index 90835e1cc21..00000000000
--- a/spec/javascripts/importer_status_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import { ImporterStatus } from '~/importer_status';
-import axios from '~/lib/utils/axios_utils';
-
-describe('Importer Status', () => {
- let instance;
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('addToImport', () => {
- const importUrl = '/import_url';
-
- beforeEach(() => {
- setFixtures(`
- <tr id="repo_123">
- <td class="import-target"></td>
- <td class="import-actions job-status">
- <button name="button" type="submit" class="btn btn-import js-add-to-import">
- </button>
- </td>
- </tr>
- `);
- spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
- spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus({
- jobsUrl: '',
- importUrl,
- });
- });
-
- it('sets table row to active after post request', done => {
- mock.onPost(importUrl).reply(200, {
- id: 1,
- full_path: '/full_path',
- });
-
- instance
- .addToImport({
- currentTarget: document.querySelector('.js-add-to-import'),
- })
- .then(() => {
- expect(document.querySelector('tr').classList.contains('table-active')).toEqual(true);
- done();
- })
- .catch(done.fail);
- });
-
- it('shows error message after failed POST request', done => {
- appendSetFixtures('<div class="flash-container"></div>');
-
- mock.onPost(importUrl).reply(422, {
- errors: 'You forgot your lunch',
- });
-
- instance
- .addToImport({
- currentTarget: document.querySelector('.js-add-to-import'),
- })
- .then(() => {
- const flashMessage = document.querySelector('.flash-text');
-
- expect(flashMessage.textContent.trim()).toEqual(
- 'An error occurred while importing project: You forgot your lunch',
- );
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('autoUpdate', () => {
- const jobsUrl = '/jobs_url';
-
- beforeEach(() => {
- const div = document.createElement('div');
- div.innerHTML = `
- <div id="project_1">
- <div class="job-status">
- </div>
- </div>
- `;
-
- document.body.appendChild(div);
-
- spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
- spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus({
- jobsUrl,
- });
- });
-
- function setupMock(importStatus) {
- mock.onGet(jobsUrl).reply(200, [
- {
- id: 1,
- import_status: importStatus,
- },
- ]);
- }
-
- function expectJobStatus(done, status) {
- instance
- .autoUpdate()
- .then(() => {
- expect(document.querySelector('#project_1').innerText.trim()).toEqual(status);
- done();
- })
- .catch(done.fail);
- }
-
- it('sets the job status to done', done => {
- setupMock('finished');
- expectJobStatus(done, 'Done');
- });
-
- it('sets the job status to scheduled', done => {
- setupMock('scheduled');
- expectJobStatus(done, 'Scheduled');
- });
-
- it('sets the job status to started', done => {
- setupMock('started');
- expectJobStatus(done, 'Started');
- });
-
- it('sets the job status to custom status', done => {
- setupMock('custom status');
- expectJobStatus(done, 'custom status');
- });
- });
-});
diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js
deleted file mode 100644
index 94e833ec83b..00000000000
--- a/spec/javascripts/labels_issue_sidebar_spec.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* eslint-disable no-new */
-
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import { shuffle } from 'lodash';
-import axios from '~/lib/utils/axios_utils';
-import IssuableContext from '~/issuable_context';
-import LabelsSelect from '~/labels_select';
-
-import '~/gl_dropdown';
-import 'select2';
-import '~/api';
-import '~/create_label';
-import '~/users_select';
-
-let saveLabelCount = 0;
-let mock;
-
-function testLabelClicks(labelOrder, done) {
- $('.edit-link')
- .get(0)
- .click();
-
- setTimeout(() => {
- const labelsInDropdown = $('.dropdown-content a');
-
- expect(labelsInDropdown.length).toBe(10);
-
- const arrayOfLabels = labelsInDropdown.get();
- const randomArrayOfLabels = shuffle(arrayOfLabels);
- randomArrayOfLabels.forEach((label, i) => {
- if (i < saveLabelCount) {
- $(label).click();
- }
- });
-
- $('.edit-link')
- .get(0)
- .click();
-
- setTimeout(() => {
- expect($('.sidebar-collapsed-icon').attr('data-original-title')).toBe(labelOrder);
- done();
- }, 0);
- }, 0);
-}
-
-describe('Issue dropdown sidebar', () => {
- preloadFixtures('static/issue_sidebar_label.html');
-
- beforeEach(() => {
- loadFixtures('static/issue_sidebar_label.html');
-
- mock = new MockAdapter(axios);
-
- new IssuableContext('{"id":1,"name":"Administrator","username":"root"}');
- new LabelsSelect();
-
- mock.onGet('/root/test/labels.json').reply(() => {
- const labels = Array(10)
- .fill()
- .map((_val, i) => ({
- id: i,
- title: `test ${i}`,
- color: '#5CB85C',
- }));
-
- return [200, labels];
- });
-
- mock.onPut('/root/test/issues/2.json').reply(() => {
- const labels = Array(saveLabelCount)
- .fill()
- .map((_val, i) => ({
- id: i,
- title: `test ${i}`,
- color: '#5CB85C',
- }));
-
- return [200, { labels }];
- });
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('changes collapsed tooltip when changing labels when less than 5', done => {
- saveLabelCount = 5;
- testLabelClicks('test 0, test 1, test 2, test 3, test 4', done);
- });
-
- it('changes collapsed tooltip when changing labels when more than 5', done => {
- saveLabelCount = 6;
- testLabelClicks('test 0, test 1, test 2, test 3, test 4, and 1 more', done);
- });
-});
diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js
deleted file mode 100644
index 82ab73c2170..00000000000
--- a/spec/javascripts/lazy_loader_spec.js
+++ /dev/null
@@ -1,244 +0,0 @@
-import LazyLoader from '~/lazy_loader';
-import { TEST_HOST } from './test_constants';
-import scrollIntoViewPromise from './helpers/scroll_into_view_promise';
-import waitForPromises from './helpers/wait_for_promises';
-import waitForAttributeChange from './helpers/wait_for_attribute_change';
-
-const execImmediately = callback => {
- callback();
-};
-
-describe('LazyLoader', function() {
- let lazyLoader = null;
-
- preloadFixtures('issues/issue_with_comment.html');
-
- describe('without IntersectionObserver', () => {
- beforeEach(function() {
- loadFixtures('issues/issue_with_comment.html');
-
- lazyLoader = new LazyLoader({
- observerNode: 'foobar',
- });
-
- spyOn(LazyLoader, 'supportsIntersectionObserver').and.callFake(() => false);
-
- spyOn(LazyLoader, 'loadImage').and.callThrough();
-
- spyOn(window, 'requestAnimationFrame').and.callFake(execImmediately);
- spyOn(window, 'requestIdleCallback').and.callFake(execImmediately);
-
- // Doing everything that happens normally in onload
- lazyLoader.register();
- });
-
- afterEach(() => {
- lazyLoader.unregister();
- });
-
- it('should copy value from data-src to src for img 1', function(done) {
- const img = document.querySelectorAll('img[data-src]')[0];
- const originalDataSrc = img.getAttribute('data-src');
-
- Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalled();
- expect(img.getAttribute('src')).toBe(originalDataSrc);
- expect(img).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should lazy load dynamically added data-src images', function(done) {
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- Promise.all([
- scrollIntoViewPromise(newImg),
- waitForAttributeChange(newImg, ['data-src', 'src']),
- ])
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalledWith(newImg);
- expect(newImg.getAttribute('src')).toBe(testPath);
- expect(newImg).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should not alter normal images', function(done) {
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.setAttribute('src', testPath);
- document.body.appendChild(newImg);
-
- scrollIntoViewPromise(newImg)
- .then(waitForPromises)
- .then(() => {
- expect(LazyLoader.loadImage).not.toHaveBeenCalledWith(newImg);
- expect(newImg).not.toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should not load dynamically added pictures if content observer is turned off', done => {
- lazyLoader.stopContentObserver();
-
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- scrollIntoViewPromise(newImg)
- .then(waitForPromises)
- .then(() => {
- expect(LazyLoader.loadImage).not.toHaveBeenCalledWith(newImg);
- expect(newImg).not.toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should load dynamically added pictures if content observer is turned off and on again', done => {
- lazyLoader.stopContentObserver();
- lazyLoader.startContentObserver();
-
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- Promise.all([
- scrollIntoViewPromise(newImg),
- waitForAttributeChange(newImg, ['data-src', 'src']),
- ])
- .then(waitForPromises)
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalledWith(newImg);
- expect(newImg).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('with IntersectionObserver', () => {
- beforeEach(function() {
- loadFixtures('issues/issue_with_comment.html');
-
- lazyLoader = new LazyLoader({
- observerNode: 'foobar',
- });
-
- spyOn(LazyLoader, 'loadImage').and.callThrough();
-
- spyOn(window, 'requestAnimationFrame').and.callFake(execImmediately);
- spyOn(window, 'requestIdleCallback').and.callFake(execImmediately);
-
- // Doing everything that happens normally in onload
- lazyLoader.register();
- });
-
- afterEach(() => {
- lazyLoader.unregister();
- });
-
- it('should copy value from data-src to src for img 1', function(done) {
- const img = document.querySelectorAll('img[data-src]')[0];
- const originalDataSrc = img.getAttribute('data-src');
-
- Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalledWith(img);
- expect(img.getAttribute('src')).toBe(originalDataSrc);
- expect(img).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should lazy load dynamically added data-src images', function(done) {
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- Promise.all([
- scrollIntoViewPromise(newImg),
- waitForAttributeChange(newImg, ['data-src', 'src']),
- ])
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalledWith(newImg);
- expect(newImg.getAttribute('src')).toBe(testPath);
- expect(newImg).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should not alter normal images', function(done) {
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.setAttribute('src', testPath);
- document.body.appendChild(newImg);
-
- scrollIntoViewPromise(newImg)
- .then(waitForPromises)
- .then(() => {
- expect(LazyLoader.loadImage).not.toHaveBeenCalledWith(newImg);
- expect(newImg).not.toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should not load dynamically added pictures if content observer is turned off', done => {
- lazyLoader.stopContentObserver();
-
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- scrollIntoViewPromise(newImg)
- .then(waitForPromises)
- .then(() => {
- expect(LazyLoader.loadImage).not.toHaveBeenCalledWith(newImg);
- expect(newImg).not.toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
-
- it('should load dynamically added pictures if content observer is turned off and on again', done => {
- lazyLoader.stopContentObserver();
- lazyLoader.startContentObserver();
-
- const newImg = document.createElement('img');
- const testPath = `${TEST_HOST}/img/testimg.png`;
- newImg.className = 'lazy';
- newImg.setAttribute('data-src', testPath);
- document.body.appendChild(newImg);
-
- Promise.all([
- scrollIntoViewPromise(newImg),
- waitForAttributeChange(newImg, ['data-src', 'src']),
- ])
- .then(() => {
- expect(LazyLoader.loadImage).toHaveBeenCalledWith(newImg);
- expect(newImg).toHaveClass('js-lazy-loaded');
- done();
- })
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js
deleted file mode 100644
index bedab0fd003..00000000000
--- a/spec/javascripts/line_highlighter_spec.js
+++ /dev/null
@@ -1,261 +0,0 @@
-/* eslint-disable dot-notation, no-return-assign, no-new, no-underscore-dangle */
-
-import $ from 'jquery';
-import LineHighlighter from '~/line_highlighter';
-
-describe('LineHighlighter', function() {
- preloadFixtures('static/line_highlighter.html');
- const clickLine = function(number, eventData = {}) {
- if ($.isEmptyObject(eventData)) {
- return $(`#L${number}`).click();
- }
- const e = $.Event('click', eventData);
- return $(`#L${number}`).trigger(e);
- };
- beforeEach(function() {
- loadFixtures('static/line_highlighter.html');
- this['class'] = new LineHighlighter();
- this.css = this['class'].highlightLineClass;
- return (this.spies = {
- __setLocationHash__: spyOn(this['class'], '__setLocationHash__').and.callFake(function() {}),
- });
- });
-
- describe('behavior', function() {
- it('highlights one line given in the URL hash', function() {
- new LineHighlighter({ hash: '#L13' });
-
- expect($('#LC13')).toHaveClass(this.css);
- });
-
- it('highlights one line given in the URL hash with given CSS class name', function() {
- const hiliter = new LineHighlighter({ hash: '#L13', highlightLineClass: 'hilite' });
-
- expect(hiliter.highlightLineClass).toBe('hilite');
- expect($('#LC13')).toHaveClass('hilite');
- expect($('#LC13')).not.toHaveClass('hll');
- });
-
- it('highlights a range of lines given in the URL hash', function() {
- new LineHighlighter({ hash: '#L5-25' });
-
- expect($(`.${this.css}`).length).toBe(21);
- for (let line = 5; line <= 25; line += 1) {
- expect($(`#LC${line}`)).toHaveClass(this.css);
- }
- });
-
- it('scrolls to the first highlighted line on initial load', function() {
- const spy = spyOn($, 'scrollTo');
- new LineHighlighter({ hash: '#L5-25' });
-
- expect(spy).toHaveBeenCalledWith('#L5', jasmine.anything());
- });
-
- it('discards click events', function() {
- const spy = spyOnEvent('a[data-line-number]', 'click');
- clickLine(13);
-
- expect(spy).toHaveBeenPrevented();
- });
-
- it('handles garbage input from the hash', function() {
- const func = function() {
- return new LineHighlighter({ fileHolderSelector: '#blob-content-holder' });
- };
-
- expect(func).not.toThrow();
- });
-
- it('handles hashchange event', () => {
- const highlighter = new LineHighlighter();
-
- spyOn(highlighter, 'highlightHash');
-
- window.dispatchEvent(new Event('hashchange'), 'L15');
-
- expect(highlighter.highlightHash).toHaveBeenCalled();
- });
- });
-
- describe('clickHandler', function() {
- it('handles clicking on a child icon element', function() {
- const spy = spyOn(this['class'], 'setHash').and.callThrough();
- $('#L13 i')
- .mousedown()
- .click();
-
- expect(spy).toHaveBeenCalledWith(13);
- expect($('#LC13')).toHaveClass(this.css);
- });
-
- describe('without shiftKey', function() {
- it('highlights one line when clicked', function() {
- clickLine(13);
-
- expect($('#LC13')).toHaveClass(this.css);
- });
-
- it('unhighlights previously highlighted lines', function() {
- clickLine(13);
- clickLine(20);
-
- expect($('#LC13')).not.toHaveClass(this.css);
- expect($('#LC20')).toHaveClass(this.css);
- });
-
- it('sets the hash', function() {
- const spy = spyOn(this['class'], 'setHash').and.callThrough();
- clickLine(13);
-
- expect(spy).toHaveBeenCalledWith(13);
- });
- });
-
- describe('with shiftKey', function() {
- it('sets the hash', function() {
- const spy = spyOn(this['class'], 'setHash').and.callThrough();
- clickLine(13);
- clickLine(20, {
- shiftKey: true,
- });
-
- expect(spy).toHaveBeenCalledWith(13);
- expect(spy).toHaveBeenCalledWith(13, 20);
- });
-
- describe('without existing highlight', function() {
- it('highlights the clicked line', function() {
- clickLine(13, {
- shiftKey: true,
- });
-
- expect($('#LC13')).toHaveClass(this.css);
- expect($(`.${this.css}`).length).toBe(1);
- });
-
- it('sets the hash', function() {
- const spy = spyOn(this['class'], 'setHash');
- clickLine(13, {
- shiftKey: true,
- });
-
- expect(spy).toHaveBeenCalledWith(13);
- });
- });
-
- describe('with existing single-line highlight', function() {
- it('uses existing line as last line when target is lesser', function() {
- clickLine(20);
- clickLine(15, {
- shiftKey: true,
- });
-
- expect($(`.${this.css}`).length).toBe(6);
- for (let line = 15; line <= 20; line += 1) {
- expect($(`#LC${line}`)).toHaveClass(this.css);
- }
- });
-
- it('uses existing line as first line when target is greater', function() {
- clickLine(5);
- clickLine(10, {
- shiftKey: true,
- });
-
- expect($(`.${this.css}`).length).toBe(6);
- for (let line = 5; line <= 10; line += 1) {
- expect($(`#LC${line}`)).toHaveClass(this.css);
- }
- });
- });
-
- describe('with existing multi-line highlight', function() {
- beforeEach(function() {
- clickLine(10, {
- shiftKey: true,
- });
- clickLine(13, {
- shiftKey: true,
- });
- });
-
- it('uses target as first line when it is less than existing first line', function() {
- clickLine(5, {
- shiftKey: true,
- });
-
- expect($(`.${this.css}`).length).toBe(6);
- for (let line = 5; line <= 10; line += 1) {
- expect($(`#LC${line}`)).toHaveClass(this.css);
- }
- });
-
- it('uses target as last line when it is greater than existing first line', function() {
- clickLine(15, {
- shiftKey: true,
- });
-
- expect($(`.${this.css}`).length).toBe(6);
- for (let line = 10; line <= 15; line += 1) {
- expect($(`#LC${line}`)).toHaveClass(this.css);
- }
- });
- });
- });
- });
-
- describe('hashToRange', function() {
- beforeEach(function() {
- this.subject = this['class'].hashToRange;
- });
-
- it('extracts a single line number from the hash', function() {
- expect(this.subject('#L5')).toEqual([5, null]);
- });
-
- it('extracts a range of line numbers from the hash', function() {
- expect(this.subject('#L5-15')).toEqual([5, 15]);
- });
-
- it('returns [null, null] when the hash is not a line number', function() {
- expect(this.subject('#foo')).toEqual([null, null]);
- });
- });
-
- describe('highlightLine', function() {
- beforeEach(function() {
- this.subject = this['class'].highlightLine;
- });
-
- it('highlights the specified line', function() {
- this.subject(13);
-
- expect($('#LC13')).toHaveClass(this.css);
- });
-
- it('accepts a String-based number', function() {
- this.subject('13');
-
- expect($('#LC13')).toHaveClass(this.css);
- });
- });
-
- describe('setHash', function() {
- beforeEach(function() {
- this.subject = this['class'].setHash;
- });
-
- it('sets the location hash for a single line', function() {
- this.subject(5);
-
- expect(this.spies.__setLocationHash__).toHaveBeenCalledWith('#L5');
- });
-
- it('sets the location hash for a range', function() {
- this.subject(5, 15);
-
- expect(this.spies.__setLocationHash__).toHaveBeenCalledWith('#L5-15');
- });
- });
-});
diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js
deleted file mode 100644
index b6173b9b171..00000000000
--- a/spec/javascripts/merge_request_spec.js
+++ /dev/null
@@ -1,187 +0,0 @@
-import $ from 'jquery';
-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';
-
-describe('MergeRequest', function() {
- describe('task lists', function() {
- let mock;
-
- preloadFixtures('merge_requests/merge_request_with_task_list.html');
- beforeEach(function() {
- loadFixtures('merge_requests/merge_request_with_task_list.html');
-
- 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, {});
-
- this.merge = new MergeRequest();
- return this.merge;
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('modifies the Markdown field', done => {
- spyOn($, 'ajax').and.stub();
- const changeEvent = document.createEvent('HTMLEvents');
- changeEvent.initEvent('change', true, true);
- $('input[type=checkbox]')
- .first()
- .attr('checked', true)[0]
- .dispatchEvent(changeEvent);
- setTimeout(() => {
- expect($('.js-task-list-field').val()).toBe(
- '- [x] Task List Item\n- [ ] \n- [ ] Task List Item 2\n',
- );
- done();
- });
- });
-
- it('ensure that task with only spaces does not get checked incorrectly', done => {
- // fixed in 'deckar01-task_list', '2.2.1' gem
- spyOn($, 'ajax').and.stub();
- const changeEvent = document.createEvent('HTMLEvents');
- changeEvent.initEvent('change', true, true);
- $('input[type=checkbox]')
- .last()
- .attr('checked', true)[0]
- .dispatchEvent(changeEvent);
- setTimeout(() => {
- expect($('.js-task-list-field').val()).toBe(
- '- [ ] Task List Item\n- [ ] \n- [x] Task List Item 2\n',
- );
- done();
- });
- });
-
- describe('tasklist', () => {
- const lineNumber = 8;
- const lineSource = '- [ ] item 8';
- const index = 3;
- const checked = true;
-
- it('submits an ajax request on tasklist:changed', done => {
- $('.js-task-list-field').trigger({
- type: 'tasklist:changed',
- detail: { lineNumber, lineSource, index, checked },
- });
-
- setTimeout(() => {
- expect(axios.patch).toHaveBeenCalledWith(
- `${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`,
- {
- merge_request: {
- description: '- [ ] Task List Item\n- [ ] \n- [ ] Task List Item 2\n',
- lock_version: 0,
- update_task: { line_number: lineNumber, line_source: lineSource, index, checked },
- },
- },
- );
-
- done();
- });
- });
-
- // https://gitlab.com/gitlab-org/gitlab/issues/34861
- // eslint-disable-next-line jasmine/no-disabled-tests
- xit('shows an error notification when tasklist update failed', done => {
- mock
- .onPatch(
- `${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`,
- )
- .reply(409, {});
-
- $('.js-task-list-field').trigger({
- type: 'tasklist:changed',
- detail: { lineNumber, lineSource, index, checked },
- });
-
- setTimeout(() => {
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- 'Someone edited this merge request at the same time you did. Please refresh the page to see changes.',
- );
-
- done();
- });
- });
- });
- });
-
- describe('class constructor', () => {
- beforeEach(() => {
- spyOn($, 'ajax').and.stub();
- });
-
- it('calls .initCloseReopenReport', () => {
- spyOn(IssuablesHelper, 'initCloseReopenReport');
-
- new MergeRequest(); // eslint-disable-line no-new
-
- expect(IssuablesHelper.initCloseReopenReport).toHaveBeenCalled();
- });
-
- it('calls .initDroplab', () => {
- const container = jasmine.createSpyObj('container', ['querySelector']);
- const dropdownTrigger = {};
- const dropdownList = {};
- const button = {};
-
- spyOn(CloseReopenReportToggle.prototype, 'initDroplab');
- spyOn(document, 'querySelector').and.returnValue(container);
- container.querySelector.and.returnValues(dropdownTrigger, dropdownList, button);
-
- new MergeRequest(); // eslint-disable-line no-new
-
- expect(document.querySelector).toHaveBeenCalledWith('.js-issuable-close-dropdown');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-toggle');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-menu');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-button');
- expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled();
- });
- });
-
- describe('hideCloseButton', () => {
- describe('merge request of another user', () => {
- beforeEach(() => {
- loadFixtures('merge_requests/merge_request_with_task_list.html');
- this.el = document.querySelector('.js-issuable-actions');
- new MergeRequest(); // eslint-disable-line no-new
- MergeRequest.hideCloseButton();
- });
-
- it('hides the dropdown close item and selects the next item', () => {
- const closeItem = this.el.querySelector('li.close-item');
- const smallCloseItem = this.el.querySelector('.js-close-item');
- const reportItem = this.el.querySelector('li.report-item');
-
- expect(closeItem).toHaveClass('hidden');
- expect(smallCloseItem).toHaveClass('hidden');
- expect(reportItem).toHaveClass('droplab-item-selected');
- expect(reportItem).not.toHaveClass('hidden');
- });
- });
-
- describe('merge request of current_user', () => {
- beforeEach(() => {
- loadFixtures('merge_requests/merge_request_of_current_user.html');
- this.el = document.querySelector('.js-issuable-actions');
- MergeRequest.hideCloseButton();
- });
-
- it('hides the close button', () => {
- const closeButton = this.el.querySelector('.btn-close');
- const smallCloseItem = this.el.querySelector('.js-close-item');
-
- expect(closeButton).toHaveClass('hidden');
- expect(smallCloseItem).toHaveClass('hidden');
- });
- });
- });
-});
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
deleted file mode 100644
index cbb61333d77..00000000000
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ /dev/null
@@ -1,283 +0,0 @@
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import MergeRequestTabs from '~/merge_request_tabs';
-import '~/commit/pipelines/pipelines_bundle';
-import '~/lib/utils/common_utils';
-import 'vendor/jquery.scrollTo';
-import initMrPage from './helpers/init_vue_mr_page_helper';
-
-describe('MergeRequestTabs', function() {
- let mrPageMock;
- const stubLocation = {};
- const setLocation = function(stubs) {
- const defaults = {
- pathname: '',
- search: '',
- hash: '',
- };
- $.extend(stubLocation, defaults, stubs || {});
- };
-
- preloadFixtures(
- 'merge_requests/merge_request_with_task_list.html',
- 'merge_requests/diff_comment.html',
- );
-
- beforeEach(function() {
- mrPageMock = initMrPage();
- this.class = new MergeRequestTabs({ stubLocation });
- setLocation();
-
- this.spies = {
- history: spyOn(window.history, 'replaceState').and.callFake(function() {}),
- };
- });
-
- afterEach(function() {
- this.class.unbindEvents();
- this.class.destroyPipelinesView();
- mrPageMock.restore();
- $('.js-merge-request-test').remove();
- });
-
- describe('opensInNewTab', function() {
- const windowTarget = '_blank';
- let clickTabParams;
- let tabUrl;
-
- beforeEach(function() {
- loadFixtures('merge_requests/merge_request_with_task_list.html');
-
- tabUrl = $('.commits-tab a').attr('href');
-
- clickTabParams = {
- metaKey: false,
- ctrlKey: false,
- which: 1,
- stopImmediatePropagation() {},
- preventDefault() {},
- currentTarget: {
- getAttribute(attr) {
- return attr === 'href' ? tabUrl : null;
- },
- },
- };
- });
-
- describe('meta click', () => {
- let metakeyEvent;
-
- beforeEach(function() {
- metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
- });
-
- it('opens page when commits link is clicked', function() {
- spyOn(window, 'open').and.callFake(function(url, name) {
- expect(url).toEqual(tabUrl);
- expect(name).toEqual(windowTarget);
- });
-
- this.class.bindEvents();
- $('.merge-request-tabs .commits-tab a').trigger(metakeyEvent);
-
- expect(window.open).toHaveBeenCalled();
- });
-
- it('opens page when commits badge is clicked', function() {
- spyOn(window, 'open').and.callFake(function(url, name) {
- expect(url).toEqual(tabUrl);
- expect(name).toEqual(windowTarget);
- });
-
- this.class.bindEvents();
- $('.merge-request-tabs .commits-tab a .badge').trigger(metakeyEvent);
-
- expect(window.open).toHaveBeenCalled();
- });
- });
-
- it('opens page tab in a new browser tab with Ctrl+Click - Windows/Linux', function() {
- spyOn(window, 'open').and.callFake(function(url, name) {
- expect(url).toEqual(tabUrl);
- expect(name).toEqual(windowTarget);
- });
-
- this.class.clickTab({ ...clickTabParams, metaKey: true });
-
- expect(window.open).toHaveBeenCalled();
- });
-
- it('opens page tab in a new browser tab with Cmd+Click - Mac', function() {
- spyOn(window, 'open').and.callFake(function(url, name) {
- expect(url).toEqual(tabUrl);
- expect(name).toEqual(windowTarget);
- });
-
- this.class.clickTab({ ...clickTabParams, ctrlKey: true });
-
- expect(window.open).toHaveBeenCalled();
- });
-
- it('opens page tab in a new browser tab with Middle-click - Mac/PC', function() {
- spyOn(window, 'open').and.callFake(function(url, name) {
- expect(url).toEqual(tabUrl);
- expect(name).toEqual(windowTarget);
- });
-
- this.class.clickTab({ ...clickTabParams, which: 2 });
-
- expect(window.open).toHaveBeenCalled();
- });
- });
-
- describe('setCurrentAction', function() {
- let mock;
-
- beforeEach(function() {
- mock = new MockAdapter(axios);
- mock.onAny().reply({ data: {} });
- this.subject = this.class.setCurrentAction;
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('changes from commits', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1/commits',
- });
-
- expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1');
- expect(this.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs');
- });
-
- it('changes from diffs', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1/diffs',
- });
-
- expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1');
- expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
- });
-
- it('changes from diffs.html', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1/diffs.html',
- });
-
- expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1');
- expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
- });
-
- it('changes from notes', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1',
- });
-
- expect(this.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs');
- expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
- });
-
- it('includes search parameters and hash string', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1/diffs',
- search: '?view=parallel',
- hash: '#L15-35',
- });
-
- expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1?view=parallel#L15-35');
- });
-
- it('replaces the current history state', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1',
- });
- const newState = this.subject('commits');
-
- expect(this.spies.history).toHaveBeenCalledWith(
- {
- url: newState,
- },
- document.title,
- newState,
- );
- });
-
- it('treats "show" like "notes"', function() {
- setLocation({
- pathname: '/foo/bar/-/merge_requests/1/commits',
- });
-
- expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1');
- });
- });
-
- describe('expandViewContainer', function() {
- beforeEach(() => {
- $('body').append(
- '<div class="content-wrapper"><div class="container-fluid container-limited"></div></div>',
- );
- });
-
- afterEach(() => {
- $('.content-wrapper').remove();
- });
-
- it('removes container-limited from containers', function() {
- this.class.expandViewContainer();
-
- expect($('.content-wrapper')).not.toContainElement('.container-limited');
- });
-
- it('does not add container-limited when fluid layout is prefered', function() {
- $('.content-wrapper .container-fluid').removeClass('container-limited');
-
- this.class.expandViewContainer(false);
-
- expect($('.content-wrapper')).not.toContainElement('.container-limited');
- });
-
- it('does remove container-limited from breadcrumbs', function() {
- $('.container-limited').addClass('breadcrumbs');
- this.class.expandViewContainer();
-
- expect($('.content-wrapper')).toContainElement('.container-limited');
- });
- });
-
- describe('tabShown', function() {
- const mainContent = document.createElement('div');
- const tabContent = document.createElement('div');
-
- beforeEach(function() {
- spyOn(mainContent, 'getBoundingClientRect').and.returnValue({ top: 10 });
- spyOn(tabContent, 'getBoundingClientRect').and.returnValue({ top: 100 });
- spyOn(document, 'querySelector').and.callFake(function(selector) {
- return selector === '.content-wrapper' ? mainContent : tabContent;
- });
- this.class.currentAction = 'commits';
- });
-
- it('calls window scrollTo with options if document has scrollBehavior', function() {
- document.documentElement.style.scrollBehavior = '';
-
- spyOn(window, 'scrollTo');
-
- this.class.tabShown('commits', 'foobar');
-
- expect(window.scrollTo.calls.first().args[0]).toEqual({ top: 39, behavior: 'smooth' });
- });
-
- it('calls window scrollTo with two args if document does not have scrollBehavior', function() {
- spyOnProperty(document.documentElement, 'style', 'get').and.returnValue({});
-
- spyOn(window, 'scrollTo');
-
- this.class.tabShown('commits', 'foobar');
-
- expect(window.scrollTo.calls.first().args).toEqual([0, 39]);
- });
- });
-});
diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js
deleted file mode 100644
index aa4a376caf7..00000000000
--- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
-import timeoutPromise from './helpers/set_timeout_promise_helper';
-
-describe('Mini Pipeline Graph Dropdown', () => {
- preloadFixtures('static/mini_dropdown_graph.html');
-
- beforeEach(() => {
- loadFixtures('static/mini_dropdown_graph.html');
- });
-
- describe('When is initialized', () => {
- it('should initialize without errors when no options are given', () => {
- const miniPipelineGraph = new MiniPipelineGraph();
-
- expect(miniPipelineGraph.dropdownListSelector).toEqual('.js-builds-dropdown-container');
- });
-
- it('should set the container as the given prop', () => {
- const container = '.foo';
-
- const miniPipelineGraph = new MiniPipelineGraph({ container });
-
- expect(miniPipelineGraph.container).toEqual(container);
- });
- });
-
- describe('When dropdown is clicked', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should call getBuildsList', () => {
- const getBuildsListSpy = spyOn(MiniPipelineGraph.prototype, 'getBuildsList').and.callFake(
- function() {},
- );
-
- new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
-
- document.querySelector('.js-builds-dropdown-button').click();
-
- expect(getBuildsListSpy).toHaveBeenCalled();
- });
-
- it('should make a request to the endpoint provided in the html', () => {
- 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]).toEqual('foobar');
- });
-
- 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();
-
- 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 => {
- mock.onGet('foobar').networkError();
-
- new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
-
- document.querySelector('.js-builds-dropdown-button').click();
-
- setTimeout(() => {
- expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/pager_spec.js b/spec/javascripts/pager_spec.js
deleted file mode 100644
index c95a8400c6c..00000000000
--- a/spec/javascripts/pager_spec.js
+++ /dev/null
@@ -1,162 +0,0 @@
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import Pager from '~/pager';
-
-describe('pager', () => {
- let axiosMock;
-
- beforeEach(() => {
- axiosMock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- axiosMock.restore();
- });
-
- describe('init', () => {
- const originalHref = window.location.href;
-
- beforeEach(() => {
- setFixtures('<div class="content_list"></div><div class="loading"></div>');
- spyOn($.fn, 'endlessScroll').and.stub();
- });
-
- afterEach(() => {
- window.history.replaceState({}, null, originalHref);
- });
-
- it('should use data-href attribute from list element', () => {
- const href = `${gl.TEST_HOST}/some_list.json`;
- setFixtures(`<div class="content_list" data-href="${href}"></div>`);
- Pager.init();
-
- expect(Pager.url).toBe(href);
- });
-
- it('should use current url if data-href attribute not provided', () => {
- const href = `${gl.TEST_HOST}/some_list`;
- spyOnDependency(Pager, 'removeParams').and.returnValue(href);
- Pager.init();
-
- expect(Pager.url).toBe(href);
- });
-
- it('should get initial offset from query parameter', () => {
- window.history.replaceState({}, null, '?offset=100');
- Pager.init();
-
- expect(Pager.offset).toBe(100);
- });
-
- it('keeps extra query parameters from url', () => {
- window.history.replaceState({}, null, '?filter=test&offset=100');
- const href = `${gl.TEST_HOST}/some_list?filter=test`;
- const removeParams = spyOnDependency(Pager, 'removeParams').and.returnValue(href);
- Pager.init();
-
- expect(removeParams).toHaveBeenCalledWith(['limit', 'offset']);
- expect(Pager.url).toEqual(href);
- });
- });
-
- describe('getOld', () => {
- const urlRegex = /(.*)some_list(.*)$/;
-
- function mockSuccess(count = 0) {
- axiosMock.onGet(urlRegex).reply(200, {
- count,
- html: '',
- });
- }
-
- function mockError() {
- axiosMock.onGet(urlRegex).networkError();
- }
-
- beforeEach(() => {
- setFixtures(
- '<div class="content_list" data-href="/some_list"></div><div class="loading"></div>',
- );
- spyOn(axios, 'get').and.callThrough();
-
- Pager.init();
- });
-
- it('shows loader while loading next page', done => {
- mockSuccess();
-
- spyOn(Pager.loading, 'show');
- Pager.getOld();
-
- setTimeout(() => {
- expect(Pager.loading.show).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('hides loader on success', done => {
- mockSuccess();
-
- spyOn(Pager.loading, 'hide');
- Pager.getOld();
-
- setTimeout(() => {
- expect(Pager.loading.hide).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('hides loader on error', done => {
- mockError();
-
- spyOn(Pager.loading, 'hide');
- Pager.getOld();
-
- setTimeout(() => {
- expect(Pager.loading.hide).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('sends request to url with offset and limit params', done => {
- Pager.offset = 100;
- Pager.limit = 20;
- Pager.getOld();
-
- setTimeout(() => {
- const [url, params] = axios.get.calls.argsFor(0);
-
- expect(params).toEqual({
- params: {
- limit: 20,
- offset: 100,
- },
- });
-
- expect(url).toBe('/some_list');
-
- done();
- });
- });
-
- it('disables if return count is less than limit', done => {
- Pager.offset = 0;
- Pager.limit = 20;
-
- mockSuccess(1);
- spyOn(Pager.loading, 'hide');
- Pager.getOld();
-
- setTimeout(() => {
- expect(Pager.loading.hide).toHaveBeenCalled();
- expect(Pager.disable).toBe(true);
-
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/pdf/index_spec.js b/spec/javascripts/pdf/index_spec.js
deleted file mode 100644
index 39cd4dacd70..00000000000
--- a/spec/javascripts/pdf/index_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import Vue from 'vue';
-
-import { FIXTURES_PATH } from 'spec/test_constants';
-import PDFLab from '~/pdf/index.vue';
-
-const pdf = `${FIXTURES_PATH}/blob/pdf/test.pdf`;
-
-const Component = Vue.extend(PDFLab);
-
-describe('PDF component', () => {
- let vm;
-
- const checkLoaded = done => {
- if (vm.loading) {
- setTimeout(() => {
- checkLoaded(done);
- }, 100);
- } else {
- done();
- }
- };
-
- describe('without PDF data', () => {
- beforeEach(done => {
- vm = new Component({
- propsData: {
- pdf: '',
- },
- });
-
- vm.$mount();
-
- checkLoaded(done);
- });
-
- it('does not render', () => {
- expect(vm.$el.tagName).toBeUndefined();
- });
- });
-
- describe('with PDF data', () => {
- beforeEach(done => {
- vm = new Component({
- propsData: {
- pdf,
- },
- });
-
- vm.$mount();
-
- checkLoaded(done);
- });
-
- it('renders pdf component', () => {
- expect(vm.$el.tagName).toBeDefined();
- });
- });
-});
diff --git a/spec/javascripts/pdf/page_spec.js b/spec/javascripts/pdf/page_spec.js
deleted file mode 100644
index cc2cc204ee3..00000000000
--- a/spec/javascripts/pdf/page_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Vue from 'vue';
-import pdfjsLib from 'pdfjs-dist/webpack';
-
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { FIXTURES_PATH } from 'spec/test_constants';
-import PageComponent from '~/pdf/page/index.vue';
-
-const testPDF = `${FIXTURES_PATH}/blob/pdf/test.pdf`;
-
-describe('Page component', () => {
- const Component = Vue.extend(PageComponent);
- let vm;
- let testPage;
-
- beforeEach(done => {
- pdfjsLib
- .getDocument(testPDF)
- .promise.then(pdf => pdf.getPage(1))
- .then(page => {
- testPage = page;
- })
- .then(done)
- .catch(done.fail);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders the page when mounting', done => {
- const promise = Promise.resolve();
- spyOn(testPage, 'render').and.returnValue({ promise });
-
- vm = mountComponent(Component, {
- page: testPage,
- number: 1,
- });
-
- expect(vm.rendering).toBe(true);
-
- promise
- .then(() => {
- expect(testPage.render).toHaveBeenCalledWith(vm.renderContext);
- expect(vm.rendering).toBe(false);
- })
- .then(done)
- .catch(done.fail);
- });
-});
diff --git a/spec/javascripts/performance_bar/index_spec.js b/spec/javascripts/performance_bar/index_spec.js
deleted file mode 100644
index 3957edce9e0..00000000000
--- a/spec/javascripts/performance_bar/index_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import '~/performance_bar/components/performance_bar_app.vue';
-import performanceBar from '~/performance_bar';
-import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
-
-describe('performance bar wrapper', () => {
- let mock;
- let vm;
-
- beforeEach(() => {
- const peekWrapper = document.createElement('div');
-
- peekWrapper.setAttribute('id', 'js-peek');
- peekWrapper.setAttribute('data-env', 'development');
- peekWrapper.setAttribute('data-request-id', '123');
- peekWrapper.setAttribute('data-peek-url', '/-/peek/results');
- peekWrapper.setAttribute('data-profile-url', '?lineprofiler=true');
-
- document.body.appendChild(peekWrapper);
-
- mock = new MockAdapter(axios);
-
- mock.onGet('/-/peek/results').reply(
- 200,
- {
- data: {
- gc: {
- invokes: 0,
- invoke_time: '0.00',
- use_size: 0,
- total_size: 0,
- total_object: 0,
- gc_time: '0.00',
- },
- host: { hostname: 'web-01' },
- },
- },
- {},
- );
-
- vm = performanceBar({ container: '#js-peek' });
- });
-
- afterEach(() => {
- vm.$destroy();
- mock.restore();
- });
-
- describe('loadRequestDetails', () => {
- beforeEach(() => {
- spyOn(vm.store, 'addRequest').and.callThrough();
- });
-
- it('does nothing if the request cannot be tracked', () => {
- spyOn(vm.store, 'canTrackRequest').and.callFake(() => false);
-
- vm.loadRequestDetails('123', 'https://gitlab.com/');
-
- expect(vm.store.addRequest).not.toHaveBeenCalled();
- });
-
- it('adds the request immediately', () => {
- vm.loadRequestDetails('123', 'https://gitlab.com/');
-
- expect(vm.store.addRequest).toHaveBeenCalledWith('123', 'https://gitlab.com/');
- });
-
- it('makes an HTTP request for the request details', () => {
- spyOn(PerformanceBarService, 'fetchRequestDetails').and.callThrough();
-
- vm.loadRequestDetails('456', 'https://gitlab.com/');
-
- expect(PerformanceBarService.fetchRequestDetails).toHaveBeenCalledWith(
- '/-/peek/results',
- '456',
- );
- });
- });
-});
diff --git a/spec/javascripts/persistent_user_callout_spec.js b/spec/javascripts/persistent_user_callout_spec.js
deleted file mode 100644
index d4cb92cacfd..00000000000
--- a/spec/javascripts/persistent_user_callout_spec.js
+++ /dev/null
@@ -1,175 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import setTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
-import axios from '~/lib/utils/axios_utils';
-import PersistentUserCallout from '~/persistent_user_callout';
-
-describe('PersistentUserCallout', () => {
- const dismissEndpoint = '/dismiss';
- const featureName = 'feature';
-
- function createFixture() {
- const fixture = document.createElement('div');
- fixture.innerHTML = `
- <div
- class="container"
- data-dismiss-endpoint="${dismissEndpoint}"
- data-feature-id="${featureName}"
- >
- <button type="button" class="js-close"></button>
- </div>
- `;
-
- return fixture;
- }
-
- function createDeferredLinkFixture() {
- const fixture = document.createElement('div');
- fixture.innerHTML = `
- <div
- class="container"
- data-dismiss-endpoint="${dismissEndpoint}"
- data-feature-id="${featureName}"
- data-defer-links="true"
- >
- <button type="button" class="js-close"></button>
- <a href="/somewhere-pleasant" target="_blank" class="deferred-link">A link</a>
- <a href="/somewhere-else" target="_blank" class="normal-link">Another link</a>
- </div>
- `;
-
- return fixture;
- }
-
- describe('dismiss', () => {
- let button;
- let mockAxios;
- let persistentUserCallout;
-
- beforeEach(() => {
- const fixture = createFixture();
- const container = fixture.querySelector('.container');
- button = fixture.querySelector('.js-close');
- mockAxios = new MockAdapter(axios);
- persistentUserCallout = new PersistentUserCallout(container);
- spyOn(persistentUserCallout.container, 'remove');
- });
-
- afterEach(() => {
- mockAxios.restore();
- });
-
- it('POSTs endpoint and removes container when clicking close', done => {
- mockAxios.onPost(dismissEndpoint).replyOnce(200);
-
- button.click();
-
- setTimeoutPromise()
- .then(() => {
- expect(persistentUserCallout.container.remove).toHaveBeenCalled();
- expect(mockAxios.history.post[0].data).toBe(
- JSON.stringify({ feature_name: featureName }),
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('invokes Flash when the dismiss request fails', done => {
- const Flash = spyOnDependency(PersistentUserCallout, 'Flash');
- mockAxios.onPost(dismissEndpoint).replyOnce(500);
-
- button.click();
-
- setTimeoutPromise()
- .then(() => {
- expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
- expect(Flash).toHaveBeenCalledWith(
- 'An error occurred while dismissing the alert. Refresh the page and try again.',
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('deferred links', () => {
- let button;
- let deferredLink;
- let normalLink;
- let mockAxios;
- let persistentUserCallout;
- let windowSpy;
-
- beforeEach(() => {
- const fixture = createDeferredLinkFixture();
- const container = fixture.querySelector('.container');
- button = fixture.querySelector('.js-close');
- deferredLink = fixture.querySelector('.deferred-link');
- normalLink = fixture.querySelector('.normal-link');
- mockAxios = new MockAdapter(axios);
- persistentUserCallout = new PersistentUserCallout(container);
- spyOn(persistentUserCallout.container, 'remove');
- windowSpy = spyOn(window, 'open').and.callFake(() => {});
- });
-
- afterEach(() => {
- mockAxios.restore();
- });
-
- it('defers loading of a link until callout is dismissed', done => {
- const { href, target } = deferredLink;
- mockAxios.onPost(dismissEndpoint).replyOnce(200);
-
- deferredLink.click();
-
- setTimeoutPromise()
- .then(() => {
- expect(windowSpy).toHaveBeenCalledWith(href, target);
- expect(persistentUserCallout.container.remove).toHaveBeenCalled();
- expect(mockAxios.history.post[0].data).toBe(
- JSON.stringify({ feature_name: featureName }),
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('does not dismiss callout on non-deferred links', done => {
- normalLink.click();
-
- setTimeoutPromise()
- .then(() => {
- expect(windowSpy).not.toHaveBeenCalled();
- expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('does not follow link when notification is closed', done => {
- mockAxios.onPost(dismissEndpoint).replyOnce(200);
-
- button.click();
-
- setTimeoutPromise()
- .then(() => {
- expect(windowSpy).not.toHaveBeenCalled();
- expect(persistentUserCallout.container.remove).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('factory', () => {
- it('returns an instance of PersistentUserCallout with the provided container property', () => {
- const fixture = createFixture();
-
- expect(PersistentUserCallout.factory(fixture) instanceof PersistentUserCallout).toBe(true);
- });
-
- it('returns undefined if container is falsey', () => {
- expect(PersistentUserCallout.factory()).toBe(undefined);
- });
- });
-});
diff --git a/spec/javascripts/read_more_spec.js b/spec/javascripts/read_more_spec.js
deleted file mode 100644
index d1d01272403..00000000000
--- a/spec/javascripts/read_more_spec.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import initReadMore from '~/read_more';
-
-describe('Read more click-to-expand functionality', () => {
- const fixtureName = 'projects/overview.html';
-
- preloadFixtures(fixtureName);
-
- beforeEach(() => {
- loadFixtures(fixtureName);
- });
-
- describe('expands target element', () => {
- it('adds "is-expanded" class to target element', () => {
- const target = document.querySelector('.read-more-container');
- const trigger = document.querySelector('.js-read-more-trigger');
- initReadMore();
-
- trigger.click();
-
- expect(target.classList.contains('is-expanded')).toEqual(true);
- });
- });
-});
diff --git a/spec/javascripts/releases/components/app_index_spec.js b/spec/javascripts/releases/components/app_index_spec.js
deleted file mode 100644
index 020937d07e5..00000000000
--- a/spec/javascripts/releases/components/app_index_spec.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import { range as rge } from 'lodash';
-import Vue from 'vue';
-import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
-import app from '~/releases/components/app_index.vue';
-import createStore from '~/releases/stores';
-import listModule from '~/releases/stores/modules/list';
-import api from '~/api';
-import { resetStore } from '../stores/modules/list/helpers';
-import {
- pageInfoHeadersWithoutPagination,
- pageInfoHeadersWithPagination,
- release,
- releases,
-} from '../mock_data';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import waitForPromises from 'spec/helpers/wait_for_promises';
-
-describe('Releases App ', () => {
- const Component = Vue.extend(app);
- let store;
- let vm;
- let releasesPagination;
-
- const props = {
- projectId: 'gitlab-ce',
- documentationPath: 'help/releases',
- illustrationPath: 'illustration/path',
- };
-
- beforeEach(() => {
- store = createStore({ modules: { list: listModule } });
- releasesPagination = rge(21).map(index => ({
- ...convertObjectPropsToCamelCase(release, { deep: true }),
- tagName: `${index}.00`,
- }));
- });
-
- afterEach(() => {
- resetStore(store);
- vm.$destroy();
- });
-
- describe('while loading', () => {
- beforeEach(() => {
- spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
- vm = mountComponentWithStore(Component, { props, store });
- });
-
- it('renders loading icon', done => {
- expect(vm.$el.querySelector('.js-loading')).not.toBeNull();
- expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
- expect(vm.$el.querySelector('.js-success-state')).toBeNull();
- expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
-
- waitForPromises()
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('with successful request', () => {
- beforeEach(() => {
- spyOn(api, 'releases').and.returnValue(
- Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination }),
- );
- vm = mountComponentWithStore(Component, { props, store });
- });
-
- it('renders success state', done => {
- waitForPromises()
- .then(() => {
- expect(vm.$el.querySelector('.js-loading')).toBeNull();
- expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
- expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
- expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('with successful request and pagination', () => {
- beforeEach(() => {
- spyOn(api, 'releases').and.returnValue(
- Promise.resolve({ data: releasesPagination, headers: pageInfoHeadersWithPagination }),
- );
- vm = mountComponentWithStore(Component, { props, store });
- });
-
- it('renders success state', done => {
- waitForPromises()
- .then(() => {
- expect(vm.$el.querySelector('.js-loading')).toBeNull();
- expect(vm.$el.querySelector('.js-empty-state')).toBeNull();
- expect(vm.$el.querySelector('.js-success-state')).not.toBeNull();
- expect(vm.$el.querySelector('.gl-pagination')).not.toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('with empty request', () => {
- beforeEach(() => {
- spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
- vm = mountComponentWithStore(Component, { props, store });
- });
-
- it('renders empty state', done => {
- waitForPromises()
- .then(() => {
- expect(vm.$el.querySelector('.js-loading')).toBeNull();
- expect(vm.$el.querySelector('.js-empty-state')).not.toBeNull();
- expect(vm.$el.querySelector('.js-success-state')).toBeNull();
- expect(vm.$el.querySelector('.gl-pagination')).toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('"New release" button', () => {
- const findNewReleaseButton = () => vm.$el.querySelector('.js-new-release-btn');
-
- beforeEach(() => {
- spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [], headers: {} }));
- });
-
- const factory = additionalProps => {
- vm = mountComponentWithStore(Component, {
- props: {
- ...props,
- ...additionalProps,
- },
- store,
- });
- };
-
- describe('when the user is allowed to create a new Release', () => {
- const newReleasePath = 'path/to/new/release';
-
- beforeEach(() => {
- factory({ newReleasePath });
- });
-
- it('renders the "New release" button', done => {
- waitForPromises()
- .then(() => {
- expect(findNewReleaseButton()).not.toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
-
- it('renders the "New release" button with the correct href', done => {
- waitForPromises()
- .then(() => {
- expect(findNewReleaseButton().getAttribute('href')).toBe(newReleasePath);
-
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('when the user is not allowed to create a new Release', () => {
- beforeEach(() => factory());
-
- it('does not render the "New release" button', done => {
- waitForPromises()
- .then(() => {
- expect(findNewReleaseButton()).toBeNull();
-
- done();
- })
- .catch(done.fail);
- });
- });
- });
-});
diff --git a/spec/javascripts/releases/mock_data.js b/spec/javascripts/releases/mock_data.js
deleted file mode 100644
index 72875dff172..00000000000
--- a/spec/javascripts/releases/mock_data.js
+++ /dev/null
@@ -1,148 +0,0 @@
-export const pageInfoHeadersWithoutPagination = {
- 'X-NEXT-PAGE': '',
- 'X-PAGE': '1',
- 'X-PER-PAGE': '20',
- 'X-PREV-PAGE': '',
- 'X-TOTAL': '19',
- 'X-TOTAL-PAGES': '1',
-};
-
-export const pageInfoHeadersWithPagination = {
- 'X-NEXT-PAGE': '2',
- 'X-PAGE': '1',
- 'X-PER-PAGE': '20',
- 'X-PREV-PAGE': '',
- 'X-TOTAL': '21',
- 'X-TOTAL-PAGES': '2',
-};
-
-export const release = {
- name: 'Bionic Beaver',
- tag_name: '18.04',
- description: '## changelog\n\n* line 1\n* line2',
- description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
- author_name: 'Release bot',
- author_email: 'release-bot@example.com',
- created_at: '2012-05-28T05:00:00-07:00',
- commit: {
- id: '2695effb5807a22ff3d138d593fd856244e155e7',
- short_id: '2695effb',
- title: 'Initial commit',
- created_at: '2017-07-26T11:08:53.000+02:00',
- parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
- message: 'Initial commit',
- author: {
- avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
- id: 482476,
- name: 'John Doe',
- path: '/johndoe',
- state: 'active',
- status_tooltip_html: null,
- username: 'johndoe',
- web_url: 'https://gitlab.com/johndoe',
- },
- authored_date: '2012-05-28T04:42:42-07:00',
- committer_name: 'Jack Smith',
- committer_email: 'jack@example.com',
- committed_date: '2012-05-28T04:42:42-07:00',
- },
- assets: {
- count: 6,
- sources: [
- {
- format: 'zip',
- url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.zip',
- },
- {
- format: 'tar.gz',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz',
- },
- {
- format: 'tar.bz2',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2',
- },
- {
- format: 'tar',
- url: 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar',
- },
- ],
- links: [
- {
- name: 'release-18.04.dmg',
- url: 'https://my-external-hosting.example.com/scrambled-url/',
- external: true,
- },
- {
- name: 'binary-linux-amd64',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
- external: false,
- },
- ],
- },
-};
-
-export const releases = [
- release,
- {
- name: 'JoJos Bizarre Adventure',
- tag_name: '19.00',
- description: '## changelog\n\n* line 1\n* line2',
- description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
- author_name: 'Release bot',
- author_email: 'release-bot@example.com',
- created_at: '2012-05-28T05:00:00-07:00',
- commit: {
- id: '2695effb5807a22ff3d138d593fd856244e155e7',
- short_id: '2695effb',
- title: 'Initial commit',
- created_at: '2017-07-26T11:08:53.000+02:00',
- parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
- message: 'Initial commit',
- author: {
- avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
- id: 482476,
- name: 'John Doe',
- path: '/johndoe',
- state: 'active',
- status_tooltip_html: null,
- username: 'johndoe',
- web_url: 'https://gitlab.com/johndoe',
- },
- authored_date: '2012-05-28T04:42:42-07:00',
- committer_name: 'Jack Smith',
- committer_email: 'jack@example.com',
- committed_date: '2012-05-28T04:42:42-07:00',
- },
- assets: {
- count: 4,
- sources: [
- {
- format: 'tar.gz',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz',
- },
- {
- format: 'tar.bz2',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2',
- },
- {
- format: 'tar',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar',
- },
- ],
- links: [
- {
- name: 'binary-linux-amd64',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
- external: false,
- },
- ],
- },
- },
-];
diff --git a/spec/javascripts/releases/stores/modules/list/actions_spec.js b/spec/javascripts/releases/stores/modules/list/actions_spec.js
deleted file mode 100644
index bf85e18997b..00000000000
--- a/spec/javascripts/releases/stores/modules/list/actions_spec.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import testAction from 'spec/helpers/vuex_action_helper';
-import {
- requestReleases,
- fetchReleases,
- receiveReleasesSuccess,
- receiveReleasesError,
-} from '~/releases/stores/modules/list/actions';
-import state from '~/releases/stores/modules/list/state';
-import * as types from '~/releases/stores/modules/list/mutation_types';
-import api from '~/api';
-import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { pageInfoHeadersWithoutPagination, releases as originalReleases } from '../../../mock_data';
-
-describe('Releases State actions', () => {
- let mockedState;
- let pageInfo;
- let releases;
-
- beforeEach(() => {
- mockedState = state();
- pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
- releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
- });
-
- describe('requestReleases', () => {
- it('should commit REQUEST_RELEASES mutation', done => {
- testAction(requestReleases, null, mockedState, [{ type: types.REQUEST_RELEASES }], [], done);
- });
- });
-
- describe('fetchReleases', () => {
- describe('success', () => {
- it('dispatches requestReleases and receiveReleasesSuccess', done => {
- spyOn(api, 'releases').and.callFake((id, options) => {
- expect(id).toEqual(1);
- expect(options.page).toEqual('1');
- return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
- });
-
- testAction(
- fetchReleases,
- { projectId: 1 },
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- payload: { data: releases, headers: pageInfoHeadersWithoutPagination },
- type: 'receiveReleasesSuccess',
- },
- ],
- done,
- );
- });
-
- it('dispatches requestReleases and receiveReleasesSuccess on page two', done => {
- spyOn(api, 'releases').and.callFake((_, options) => {
- expect(options.page).toEqual('2');
- return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
- });
-
- testAction(
- fetchReleases,
- { page: '2', projectId: 1 },
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- payload: { data: releases, headers: pageInfoHeadersWithoutPagination },
- type: 'receiveReleasesSuccess',
- },
- ],
- done,
- );
- });
- });
-
- describe('error', () => {
- it('dispatches requestReleases and receiveReleasesError', done => {
- spyOn(api, 'releases').and.returnValue(Promise.reject());
-
- testAction(
- fetchReleases,
- { projectId: null },
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- type: 'receiveReleasesError',
- },
- ],
- done,
- );
- });
- });
- });
-
- describe('receiveReleasesSuccess', () => {
- it('should commit RECEIVE_RELEASES_SUCCESS mutation', done => {
- testAction(
- receiveReleasesSuccess,
- { data: releases, headers: pageInfoHeadersWithoutPagination },
- mockedState,
- [{ type: types.RECEIVE_RELEASES_SUCCESS, payload: { pageInfo, data: releases } }],
- [],
- done,
- );
- });
- });
-
- describe('receiveReleasesError', () => {
- it('should commit RECEIVE_RELEASES_ERROR mutation', done => {
- testAction(
- receiveReleasesError,
- null,
- mockedState,
- [{ type: types.RECEIVE_RELEASES_ERROR }],
- [],
- done,
- );
- });
- });
-});
diff --git a/spec/javascripts/releases/stores/modules/list/helpers.js b/spec/javascripts/releases/stores/modules/list/helpers.js
deleted file mode 100644
index 435ca36047e..00000000000
--- a/spec/javascripts/releases/stores/modules/list/helpers.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import state from '~/releases/stores/modules/list/state';
-
-// eslint-disable-next-line import/prefer-default-export
-export const resetStore = store => {
- store.replaceState(state());
-};
diff --git a/spec/javascripts/releases/stores/modules/list/mutations_spec.js b/spec/javascripts/releases/stores/modules/list/mutations_spec.js
deleted file mode 100644
index 3035b916ff6..00000000000
--- a/spec/javascripts/releases/stores/modules/list/mutations_spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import state from '~/releases/stores/modules/list/state';
-import mutations from '~/releases/stores/modules/list/mutations';
-import * as types from '~/releases/stores/modules/list/mutation_types';
-import { parseIntPagination } from '~/lib/utils/common_utils';
-import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data';
-
-describe('Releases Store Mutations', () => {
- let stateCopy;
- let pageInfo;
-
- beforeEach(() => {
- stateCopy = state();
- pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
- });
-
- describe('REQUEST_RELEASES', () => {
- it('sets isLoading to true', () => {
- mutations[types.REQUEST_RELEASES](stateCopy);
-
- expect(stateCopy.isLoading).toEqual(true);
- });
- });
-
- describe('RECEIVE_RELEASES_SUCCESS', () => {
- beforeEach(() => {
- mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, { pageInfo, data: releases });
- });
-
- it('sets is loading to false', () => {
- expect(stateCopy.isLoading).toEqual(false);
- });
-
- it('sets hasError to false', () => {
- expect(stateCopy.hasError).toEqual(false);
- });
-
- it('sets data', () => {
- expect(stateCopy.releases).toEqual(releases);
- });
-
- it('sets pageInfo', () => {
- expect(stateCopy.pageInfo).toEqual(pageInfo);
- });
- });
-
- describe('RECEIVE_RELEASES_ERROR', () => {
- it('resets data', () => {
- mutations[types.RECEIVE_RELEASES_ERROR](stateCopy);
-
- expect(stateCopy.isLoading).toEqual(false);
- expect(stateCopy.releases).toEqual([]);
- expect(stateCopy.pageInfo).toEqual({});
- });
- });
-});
diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js
deleted file mode 100644
index 9565e3ce546..00000000000
--- a/spec/javascripts/right_sidebar_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import '~/commons/bootstrap';
-import axios from '~/lib/utils/axios_utils';
-import Sidebar from '~/right_sidebar';
-
-let $aside = null;
-let $toggle = null;
-let $icon = null;
-let $page = null;
-let $labelsIcon = null;
-
-const assertSidebarState = function(state) {
- const shouldBeExpanded = state === 'expanded';
- const shouldBeCollapsed = state === 'collapsed';
- expect($aside.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded);
- expect($page.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded);
- expect($icon.hasClass('fa-angle-double-right')).toBe(shouldBeExpanded);
- expect($aside.hasClass('right-sidebar-collapsed')).toBe(shouldBeCollapsed);
- expect($page.hasClass('right-sidebar-collapsed')).toBe(shouldBeCollapsed);
- expect($icon.hasClass('fa-angle-double-left')).toBe(shouldBeCollapsed);
-};
-
-describe('RightSidebar', function() {
- describe('fixture tests', () => {
- const fixtureName = 'issues/open-issue.html';
- preloadFixtures(fixtureName);
- loadJSONFixtures('todos/todos.json');
- let mock;
-
- beforeEach(function() {
- loadFixtures(fixtureName);
- mock = new MockAdapter(axios);
- new Sidebar(); // eslint-disable-line no-new
- $aside = $('.right-sidebar');
- $page = $('.layout-page');
- $icon = $aside.find('i');
- $toggle = $aside.find('.js-sidebar-toggle');
- $labelsIcon = $aside.find('.sidebar-collapsed-icon');
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should expand/collapse the sidebar when arrow is clicked', function() {
- assertSidebarState('expanded');
- $toggle.click();
- assertSidebarState('collapsed');
- $toggle.click();
- assertSidebarState('expanded');
- });
-
- it('should float over the page and when sidebar icons clicked', function() {
- $labelsIcon.click();
- assertSidebarState('expanded');
- });
-
- it('should collapse when the icon arrow clicked while it is floating on page', function() {
- $labelsIcon.click();
- assertSidebarState('expanded');
- $toggle.click();
- assertSidebarState('collapsed');
- });
-
- it('should broadcast todo:toggle event when add todo clicked', function(done) {
- const todos = getJSONFixture('todos/todos.json');
- mock.onPost(/(.*)\/todos$/).reply(200, todos);
-
- const todoToggleSpy = spyOnEvent(document, 'todo:toggle');
-
- $('.issuable-sidebar-header .js-issuable-todo').click();
-
- setTimeout(() => {
- expect(todoToggleSpy.calls.count()).toEqual(1);
-
- done();
- });
- });
-
- it('should not hide collapsed icons', () => {
- [].forEach.call(document.querySelectorAll('.sidebar-collapsed-icon'), el => {
- expect(el.querySelector('.fa, svg').classList.contains('hidden')).toBeFalsy();
- });
- });
- });
-});
diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js
deleted file mode 100644
index 4f42d4880e8..00000000000
--- a/spec/javascripts/search_autocomplete_spec.js
+++ /dev/null
@@ -1,215 +0,0 @@
-/* eslint-disable no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign */
-
-import $ from 'jquery';
-import '~/gl_dropdown';
-import initSearchAutocomplete from '~/search_autocomplete';
-import '~/lib/utils/common_utils';
-
-describe('Search autocomplete dropdown', () => {
- let widget = null;
-
- const userName = 'root';
-
- const userId = 1;
-
- const dashboardIssuesPath = '/dashboard/issues';
-
- const dashboardMRsPath = '/dashboard/merge_requests';
-
- const projectIssuesPath = '/gitlab-org/gitlab-foss/issues';
-
- const projectMRsPath = '/gitlab-org/gitlab-foss/-/merge_requests';
-
- const groupIssuesPath = '/groups/gitlab-org/-/issues';
-
- const groupMRsPath = '/groups/gitlab-org/-/merge_requests';
-
- const projectName = 'GitLab Community Edition';
-
- const groupName = 'Gitlab Org';
-
- const removeBodyAttributes = function() {
- const $body = $('body');
-
- $body.removeAttr('data-page');
- $body.removeAttr('data-project');
- $body.removeAttr('data-group');
- };
-
- // Add required attributes to body before starting the test.
- // section would be dashboard|group|project
- const addBodyAttributes = function(section) {
- if (section == null) {
- section = 'dashboard';
- }
-
- const $body = $('body');
- removeBodyAttributes();
- switch (section) {
- case 'dashboard':
- return $body.attr('data-page', 'root:index');
- case 'group':
- $body.attr('data-page', 'groups:show');
- return $body.data('group', 'gitlab-org');
- case 'project':
- $body.attr('data-page', 'projects:show');
- return $body.data('project', 'gitlab-ce');
- }
- };
-
- const disableProjectIssues = function() {
- document.querySelector('.js-search-project-options').setAttribute('data-issues-disabled', true);
- };
-
- // Mock `gl` object in window for dashboard specific page. App code will need it.
- const mockDashboardOptions = function() {
- window.gl || (window.gl = {});
- return (window.gl.dashboardOptions = {
- issuesPath: dashboardIssuesPath,
- mrPath: dashboardMRsPath,
- });
- };
-
- // Mock `gl` object in window for project specific page. App code will need it.
- const mockProjectOptions = function() {
- window.gl || (window.gl = {});
- return (window.gl.projectOptions = {
- 'gitlab-ce': {
- issuesPath: projectIssuesPath,
- mrPath: projectMRsPath,
- projectName,
- },
- });
- };
-
- const mockGroupOptions = function() {
- window.gl || (window.gl = {});
- return (window.gl.groupOptions = {
- 'gitlab-org': {
- issuesPath: groupIssuesPath,
- mrPath: groupMRsPath,
- projectName: groupName,
- },
- });
- };
-
- const assertLinks = function(list, issuesPath, mrsPath) {
- if (issuesPath) {
- const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_username=${userName}"]`;
- const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_username=${userName}"]`;
-
- expect(list.find(issuesAssignedToMeLink).length).toBe(1);
- expect(list.find(issuesAssignedToMeLink).text()).toBe('Issues assigned to me');
- expect(list.find(issuesIHaveCreatedLink).length).toBe(1);
- expect(list.find(issuesIHaveCreatedLink).text()).toBe("Issues I've created");
- }
- const mrsAssignedToMeLink = `a[href="${mrsPath}/?assignee_username=${userName}"]`;
- const mrsIHaveCreatedLink = `a[href="${mrsPath}/?author_username=${userName}"]`;
-
- expect(list.find(mrsAssignedToMeLink).length).toBe(1);
- expect(list.find(mrsAssignedToMeLink).text()).toBe('Merge requests assigned to me');
- expect(list.find(mrsIHaveCreatedLink).length).toBe(1);
- expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created");
- };
-
- preloadFixtures('static/search_autocomplete.html');
- beforeEach(function() {
- loadFixtures('static/search_autocomplete.html');
-
- window.gon = {};
- window.gon.current_user_id = userId;
- window.gon.current_username = userName;
-
- return (widget = initSearchAutocomplete());
- });
-
- afterEach(function() {
- // Undo what we did to the shared <body>
- removeBodyAttributes();
- window.gon = {};
- });
-
- it('should show Dashboard specific dropdown menu', function() {
- addBodyAttributes();
- mockDashboardOptions();
- widget.searchInput.triggerHandler('focus');
- const list = widget.wrap.find('.dropdown-menu').find('ul');
- return assertLinks(list, dashboardIssuesPath, dashboardMRsPath);
- });
-
- it('should show Group specific dropdown menu', function() {
- addBodyAttributes('group');
- mockGroupOptions();
- widget.searchInput.triggerHandler('focus');
- const list = widget.wrap.find('.dropdown-menu').find('ul');
- return assertLinks(list, groupIssuesPath, groupMRsPath);
- });
-
- it('should show Project specific dropdown menu', function() {
- addBodyAttributes('project');
- mockProjectOptions();
- widget.searchInput.triggerHandler('focus');
- const list = widget.wrap.find('.dropdown-menu').find('ul');
- return assertLinks(list, projectIssuesPath, projectMRsPath);
- });
-
- it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() {
- addBodyAttributes('project');
- disableProjectIssues();
- mockProjectOptions();
- widget.searchInput.triggerHandler('focus');
- const list = widget.wrap.find('.dropdown-menu').find('ul');
- assertLinks(list, null, projectMRsPath);
- });
-
- it('should not show category related menu if there is text in the input', function() {
- addBodyAttributes('project');
- mockProjectOptions();
- widget.searchInput.val('help');
- widget.searchInput.triggerHandler('focus');
- const list = widget.wrap.find('.dropdown-menu').find('ul');
- const link = `a[href='${projectIssuesPath}/?assignee_username=${userName}']`;
-
- expect(list.find(link).length).toBe(0);
- });
-
- it('should not submit the search form when selecting an autocomplete row with the keyboard', function() {
- const ENTER = 13;
- const DOWN = 40;
- addBodyAttributes();
- mockDashboardOptions(true);
- const submitSpy = spyOnEvent('form', 'submit');
- widget.searchInput.triggerHandler('focus');
- widget.wrap.trigger($.Event('keydown', { which: DOWN }));
- const enterKeyEvent = $.Event('keydown', { which: ENTER });
- widget.searchInput.trigger(enterKeyEvent);
- // This does not currently catch failing behavior. For security reasons,
- // browsers will not trigger default behavior (form submit, in this
- // example) on JavaScript-created keypresses.
- expect(submitSpy).not.toHaveBeenTriggered();
- });
-
- describe('disableAutocomplete', function() {
- beforeEach(function() {
- widget.enableAutocomplete();
- });
-
- it('should close the Dropdown', function() {
- const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown');
-
- widget.dropdown.addClass('show');
- widget.disableAutocomplete();
-
- expect(toggleSpy).toHaveBeenCalledWith('toggle');
- });
- });
-
- describe('enableAutocomplete', function() {
- it('should open the Dropdown', function() {
- const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown');
- widget.enableAutocomplete();
-
- expect(toggleSpy).toHaveBeenCalledWith('toggle');
- });
- });
-});
diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js
deleted file mode 100644
index df7012bb659..00000000000
--- a/spec/javascripts/shortcuts_spec.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import $ from 'jquery';
-import Shortcuts from '~/behaviors/shortcuts/shortcuts';
-
-describe('Shortcuts', () => {
- const fixtureName = 'snippets/show.html';
- const createEvent = (type, target) =>
- $.Event(type, {
- target,
- });
-
- preloadFixtures(fixtureName);
-
- describe('toggleMarkdownPreview', () => {
- beforeEach(() => {
- loadFixtures(fixtureName);
-
- spyOnEvent('.js-new-note-form .js-md-preview-button', 'focus');
- spyOnEvent('.edit-note .js-md-preview-button', 'focus');
-
- new Shortcuts(); // eslint-disable-line no-new
- });
-
- it('focuses preview button in form', () => {
- Shortcuts.toggleMarkdownPreview(
- createEvent('KeyboardEvent', document.querySelector('.js-new-note-form .js-note-text')),
- );
-
- expect('focus').toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button');
- });
-
- it('focues preview button inside edit comment form', done => {
- document.querySelector('.js-note-edit').click();
-
- setTimeout(() => {
- Shortcuts.toggleMarkdownPreview(
- createEvent('KeyboardEvent', document.querySelector('.edit-note .js-note-text')),
- );
-
- expect('focus').not.toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button');
- expect('focus').toHaveBeenTriggeredOn('.edit-note .js-md-preview-button');
-
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js
deleted file mode 100644
index 966ae55ce14..00000000000
--- a/spec/javascripts/signin_tabs_memoizer_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import AccessorUtilities from '~/lib/utils/accessor';
-import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
-import trackData from '~/pages/sessions/new/index';
-import Tracking from '~/tracking';
-
-describe('SigninTabsMemoizer', () => {
- const fixtureTemplate = 'static/signin_tabs.html';
- const tabSelector = 'ul.new-session-tabs';
- const currentTabKey = 'current_signin_tab';
- let memo;
-
- function createMemoizer() {
- memo = new SigninTabsMemoizer({
- currentTabKey,
- tabSelector,
- });
- return memo;
- }
-
- preloadFixtures(fixtureTemplate);
-
- beforeEach(() => {
- loadFixtures(fixtureTemplate);
-
- spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true);
- });
-
- it('does nothing if no tab was previously selected', () => {
- createMemoizer();
-
- expect(document.querySelector(`${tabSelector} > li.active a`).getAttribute('href')).toEqual(
- '#ldap',
- );
- });
-
- it('shows last selected tab on boot', () => {
- createMemoizer().saveData('#ldap');
- const fakeTab = {
- click: () => {},
- };
- spyOn(document, 'querySelector').and.returnValue(fakeTab);
- spyOn(fakeTab, 'click');
-
- memo.bootstrap();
-
- // verify that triggers click on the last selected tab
- expect(document.querySelector).toHaveBeenCalledWith(`${tabSelector} a[href="#ldap"]`);
- expect(fakeTab.click).toHaveBeenCalled();
- });
-
- it('clicks the first tab if value in local storage is bad', () => {
- createMemoizer().saveData('#bogus');
- const fakeTab = {
- click: () => {},
- };
- spyOn(document, 'querySelector').and.callFake(selector =>
- selector === `${tabSelector} a[href="#bogus"]` ? null : fakeTab,
- );
- spyOn(fakeTab, 'click');
-
- memo.bootstrap();
-
- // verify that triggers click on stored selector and fallback
- expect(document.querySelector.calls.allArgs()).toEqual([
- ['ul.new-session-tabs a[href="#bogus"]'],
- ['ul.new-session-tabs a'],
- ]);
-
- expect(fakeTab.click).toHaveBeenCalled();
- });
-
- it('saves last selected tab on change', () => {
- createMemoizer();
-
- document.querySelector('a[href="#login-pane"]').click();
-
- expect(memo.readData()).toEqual('#login-pane');
- });
-
- it('overrides last selected tab with hash tag when given', () => {
- window.location.hash = '#ldap';
- createMemoizer();
-
- expect(memo.readData()).toEqual('#ldap');
- });
-
- describe('class constructor', () => {
- beforeEach(() => {
- memo = createMemoizer();
- });
-
- it('should set .isLocalStorageAvailable', () => {
- expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
- expect(memo.isLocalStorageAvailable).toBe(true);
- });
- });
-
- describe('trackData', () => {
- beforeEach(() => {
- spyOn(Tracking, 'event');
- });
-
- describe('with tracking data', () => {
- beforeEach(() => {
- gon.tracking_data = {
- category: 'Growth::Acquisition::Experiment::SignUpFlow',
- action: 'start',
- label: 'uuid',
- property: 'control_group',
- };
- trackData();
- });
-
- it('should track data when the "click" event of the register tab is triggered', () => {
- document.querySelector('a[href="#register-pane"]').click();
-
- expect(Tracking.event).toHaveBeenCalledWith(
- 'Growth::Acquisition::Experiment::SignUpFlow',
- 'start',
- {
- label: 'uuid',
- property: 'control_group',
- },
- );
- });
- });
-
- describe('without tracking data', () => {
- beforeEach(() => {
- gon.tracking_data = undefined;
- trackData();
- });
-
- it('should not track data when the "click" event of the register tab is triggered', () => {
- document.querySelector('a[href="#register-pane"]').click();
-
- expect(Tracking.event).not.toHaveBeenCalled();
- });
- });
- });
-
- describe('saveData', () => {
- beforeEach(() => {
- memo = {
- currentTabKey,
- };
-
- spyOn(localStorage, 'setItem');
- });
-
- describe('if .isLocalStorageAvailable is `false`', () => {
- beforeEach(function() {
- memo.isLocalStorageAvailable = false;
-
- SigninTabsMemoizer.prototype.saveData.call(memo);
- });
-
- it('should not call .setItem', () => {
- expect(localStorage.setItem).not.toHaveBeenCalled();
- });
- });
-
- describe('if .isLocalStorageAvailable is `true`', () => {
- const value = 'value';
-
- beforeEach(function() {
- memo.isLocalStorageAvailable = true;
-
- SigninTabsMemoizer.prototype.saveData.call(memo, value);
- });
-
- it('should call .setItem', () => {
- expect(localStorage.setItem).toHaveBeenCalledWith(currentTabKey, value);
- });
- });
- });
-
- describe('readData', () => {
- const itemValue = 'itemValue';
- let readData;
-
- beforeEach(() => {
- memo = {
- currentTabKey,
- };
-
- spyOn(localStorage, 'getItem').and.returnValue(itemValue);
- });
-
- describe('if .isLocalStorageAvailable is `false`', () => {
- beforeEach(function() {
- memo.isLocalStorageAvailable = false;
-
- readData = SigninTabsMemoizer.prototype.readData.call(memo);
- });
-
- it('should not call .getItem and should return `null`', () => {
- expect(localStorage.getItem).not.toHaveBeenCalled();
- expect(readData).toBe(null);
- });
- });
-
- describe('if .isLocalStorageAvailable is `true`', () => {
- beforeEach(function() {
- memo.isLocalStorageAvailable = true;
-
- readData = SigninTabsMemoizer.prototype.readData.call(memo);
- });
-
- it('should call .getItem and return the localStorage value', () => {
- expect(window.localStorage.getItem).toHaveBeenCalledWith(currentTabKey);
- expect(readData).toBe(itemValue);
- });
- });
- });
-});
diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js
deleted file mode 100644
index dc3c547c632..00000000000
--- a/spec/javascripts/todos_spec.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import Todos from '~/pages/dashboard/todos/index/todos';
-import '~/lib/utils/common_utils';
-import '~/gl_dropdown';
-import axios from '~/lib/utils/axios_utils';
-import { addDelimiter } from '~/lib/utils/text_utility';
-
-const TEST_COUNT_BIG = 2000;
-const TEST_DONE_COUNT_BIG = 7300;
-
-describe('Todos', () => {
- preloadFixtures('todos/todos.html');
- let todoItem;
- let mock;
-
- beforeEach(() => {
- loadFixtures('todos/todos.html');
- todoItem = document.querySelector('.todos-list .todo');
- mock = new MockAdapter(axios);
-
- return new Todos();
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('goToTodoUrl', () => {
- it('opens the todo url', done => {
- const todoLink = todoItem.dataset.url;
-
- spyOnDependency(Todos, 'visitUrl').and.callFake(url => {
- expect(url).toEqual(todoLink);
- done();
- });
-
- todoItem.click();
- });
-
- describe('meta click', () => {
- let visitUrlSpy;
- let windowOpenSpy;
- let metakeyEvent;
-
- beforeEach(() => {
- metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
- visitUrlSpy = spyOnDependency(Todos, 'visitUrl').and.callFake(() => {});
- windowOpenSpy = spyOn(window, 'open').and.callFake(() => {});
- });
-
- it('opens the todo url in another tab', () => {
- const todoLink = todoItem.dataset.url;
-
- $('.todos-list .todo').trigger(metakeyEvent);
-
- expect(visitUrlSpy).not.toHaveBeenCalled();
- expect(windowOpenSpy).toHaveBeenCalledWith(todoLink, '_blank');
- });
-
- it('run native funcionality when avatar is clicked', () => {
- $('.todos-list a').on('click', e => e.preventDefault());
- $('.todos-list img').trigger(metakeyEvent);
-
- expect(visitUrlSpy).not.toHaveBeenCalled();
- expect(windowOpenSpy).not.toHaveBeenCalled();
- });
- });
-
- describe('on done todo click', () => {
- let onToggleSpy;
-
- beforeEach(done => {
- const el = document.querySelector('.js-done-todo');
- const path = el.dataset.href;
-
- // Arrange
- mock
- .onDelete(path)
- .replyOnce(200, { count: TEST_COUNT_BIG, done_count: TEST_DONE_COUNT_BIG });
- onToggleSpy = jasmine.createSpy('onToggle');
- $(document).on('todo:toggle', onToggleSpy);
-
- // Act
- el.click();
-
- // Wait for axios and HTML to udpate
- setImmediate(done);
- });
-
- it('dispatches todo:toggle', () => {
- expect(onToggleSpy).toHaveBeenCalledWith(jasmine.anything(), TEST_COUNT_BIG);
- });
-
- it('updates pending text', () => {
- expect(document.querySelector('.todos-pending .badge').innerHTML).toEqual(
- addDelimiter(TEST_COUNT_BIG),
- );
- });
-
- it('updates done text', () => {
- expect(document.querySelector('.todos-done .badge').innerHTML).toEqual(
- addDelimiter(TEST_DONE_COUNT_BIG),
- );
- });
- });
- });
-});
diff --git a/spec/javascripts/toggle_buttons_spec.js b/spec/javascripts/toggle_buttons_spec.js
deleted file mode 100644
index 09756ff76ec..00000000000
--- a/spec/javascripts/toggle_buttons_spec.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import $ from 'jquery';
-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/user_popovers_spec.js b/spec/javascripts/user_popovers_spec.js
deleted file mode 100644
index 6ac22fca2d3..00000000000
--- a/spec/javascripts/user_popovers_spec.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import initUserPopovers from '~/user_popovers';
-import UsersCache from '~/lib/utils/users_cache';
-
-describe('User Popovers', () => {
- const fixtureTemplate = 'merge_requests/merge_request_with_mentions.html';
- preloadFixtures(fixtureTemplate);
-
- const selector = '.js-user-link, .gfm-project_member';
-
- const dummyUser = { name: 'root' };
- const dummyUserStatus = { message: 'active' };
-
- let popovers;
-
- const triggerEvent = (eventName, el) => {
- const event = new MouseEvent(eventName, {
- bubbles: true,
- cancelable: true,
- view: window,
- });
-
- el.dispatchEvent(event);
- };
-
- beforeEach(() => {
- loadFixtures(fixtureTemplate);
-
- const usersCacheSpy = () => Promise.resolve(dummyUser);
- spyOn(UsersCache, 'retrieveById').and.callFake(userId => usersCacheSpy(userId));
-
- const userStatusCacheSpy = () => Promise.resolve(dummyUserStatus);
- spyOn(UsersCache, 'retrieveStatusById').and.callFake(userId => userStatusCacheSpy(userId));
-
- popovers = initUserPopovers(document.querySelectorAll(selector));
- });
-
- it('initializes a popover for each user link with a user id', () => {
- const linksWithUsers = Array.from(document.querySelectorAll(selector)).filter(
- ({ dataset }) => dataset.user || dataset.userId,
- );
-
- expect(linksWithUsers.length).toBe(popovers.length);
- });
-
- it('does not initialize the user popovers twice for the same element', () => {
- const newPopovers = initUserPopovers(document.querySelectorAll(selector));
- const samePopovers = popovers.every((popover, index) => newPopovers[index] === popover);
-
- expect(samePopovers).toBe(true);
- });
-
- describe('when user link emits mouseenter event', () => {
- let userLink;
-
- beforeEach(() => {
- userLink = document.querySelector(selector);
-
- triggerEvent('mouseenter', userLink);
- });
-
- it('removes title attribute from user links', () => {
- expect(userLink.getAttribute('title')).toBeFalsy();
- expect(userLink.dataset.originalTitle).toBeFalsy();
- });
-
- it('populates popovers with preloaded user data', () => {
- const { name, userId, username } = userLink.dataset;
- const [firstPopover] = popovers;
-
- expect(firstPopover.$props.user).toEqual(
- jasmine.objectContaining({
- name,
- userId,
- username,
- }),
- );
- });
-
- it('fetches user info and status from the user cache', () => {
- const { userId } = userLink.dataset;
-
- expect(UsersCache.retrieveById).toHaveBeenCalledWith(userId);
- expect(UsersCache.retrieveStatusById).toHaveBeenCalledWith(userId);
- });
- });
-
- it('removes aria-describedby attribute from the user link on mouseleave', () => {
- const userLink = document.querySelector(selector);
-
- userLink.setAttribute('aria-describedby', 'popover');
- triggerEvent('mouseleave', userLink);
-
- expect(userLink.getAttribute('aria-describedby')).toBe(null);
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js
deleted file mode 100644
index f78fcfb52b4..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_alert_message_spec.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlLink } from '@gitlab/ui';
-import MrWidgetAlertMessage from '~/vue_merge_request_widget/components/mr_widget_alert_message.vue';
-
-describe('MrWidgetAlertMessage', () => {
- let wrapper;
-
- beforeEach(() => {
- const localVue = createLocalVue();
-
- wrapper = shallowMount(localVue.extend(MrWidgetAlertMessage), {
- propsData: {},
- localVue,
- });
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when type is not provided', () => {
- it('should render a red message', done => {
- wrapper.vm.$nextTick(() => {
- expect(wrapper.classes()).toContain('danger_message');
- expect(wrapper.classes()).not.toContain('warning_message');
- done();
- });
- });
- });
-
- describe('when type === "danger"', () => {
- it('should render a red message', done => {
- wrapper.setProps({ type: 'danger' });
- wrapper.vm.$nextTick(() => {
- expect(wrapper.classes()).toContain('danger_message');
- expect(wrapper.classes()).not.toContain('warning_message');
- done();
- });
- });
- });
-
- describe('when type === "warning"', () => {
- it('should render a red message', done => {
- wrapper.setProps({ type: 'warning' });
- wrapper.vm.$nextTick(() => {
- expect(wrapper.classes()).toContain('warning_message');
- expect(wrapper.classes()).not.toContain('danger_message');
- done();
- });
- });
- });
-
- describe('when helpPath is not provided', () => {
- it('should not render a help icon/link', done => {
- wrapper.vm.$nextTick(() => {
- const link = wrapper.find(GlLink);
-
- expect(link.exists()).toBe(false);
- done();
- });
- });
- });
-
- describe('when helpPath is provided', () => {
- it('should render a help icon/link', done => {
- wrapper.setProps({ helpPath: '/path/to/help/docs' });
- wrapper.vm.$nextTick(() => {
- const link = wrapper.find(GlLink);
-
- expect(link.exists()).toBe(true);
- expect(link.attributes().href).toBe('/path/to/help/docs');
- done();
- });
- });
- });
-});
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
deleted file mode 100644
index a942a9dec87..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import MrWidgetAuthor from '~/vue_merge_request_widget/components/mr_widget_author.vue';
-
-describe('MrWidgetAuthor', () => {
- let vm;
-
- beforeEach(() => {
- const Component = Vue.extend(MrWidgetAuthor);
-
- vm = mountComponent(Component, {
- author: {
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://localhost:3000/root',
- avatarUrl:
- 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- },
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- 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
deleted file mode 100644
index 55af2baa924..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import MrWidgetAuthorTime from '~/vue_merge_request_widget/components/mr_widget_author_time.vue';
-
-describe('MrWidgetAuthorTime', () => {
- let vm;
-
- beforeEach(() => {
- const Component = Vue.extend(MrWidgetAuthorTime);
-
- 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',
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders provided action text', () => {
- expect(vm.$el.textContent).toContain('Merged by');
- });
-
- it('renders author', () => {
- expect(vm.$el.textContent).toContain('Administrator');
- });
-
- it('renders provided time', () => {
- expect(vm.$el.querySelector('time').getAttribute('data-original-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
deleted file mode 100644
index 3cbaa47c832..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
+++ /dev/null
@@ -1,313 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue';
-
-describe('MRWidgetHeader', () => {
- let vm;
- let Component;
-
- beforeEach(() => {
- Component = Vue.extend(headerComponent);
- });
-
- afterEach(() => {
- vm.$destroy();
- gon.relative_url_root = '';
- });
-
- const expectDownloadDropdownItems = () => {
- const downloadEmailPatchesEl = vm.$el.querySelector('.js-download-email-patches');
- const downloadPlainDiffEl = vm.$el.querySelector('.js-download-plain-diff');
-
- expect(downloadEmailPatchesEl.textContent.trim()).toEqual('Email patches');
- expect(downloadEmailPatchesEl.getAttribute('href')).toEqual('/mr/email-patches');
- expect(downloadPlainDiffEl.textContent.trim()).toEqual('Plain diff');
- expect(downloadPlainDiffEl.getAttribute('href')).toEqual('/mr/plainDiffPath');
- };
-
- describe('computed', () => {
- 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',
- statusPath: 'abc',
- },
- });
-
- 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',
- statusPath: 'abc',
- },
- });
-
- expect(vm.shouldShowCommitsBehindText).toEqual(false);
- });
- });
-
- describe('commitsBehindText', () => {
- 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',
- targetBranchPath: '/foo/bar/master',
- statusPath: 'abc',
- },
- });
-
- expect(vm.commitsBehindText).toEqual(
- 'The source branch is <a href="/foo/bar/master">1 commit behind</a> the target branch',
- );
- });
-
- 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',
- targetBranchPath: '/foo/bar/master',
- statusPath: 'abc',
- },
- });
-
- expect(vm.commitsBehindText).toEqual(
- 'The source branch is <a href="/foo/bar/master">2 commits behind</a> the target branch',
- );
- });
- });
- });
-
- describe('template', () => {
- 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',
- statusPath: 'abc',
- },
- });
- });
-
- 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', () => {
- const mrDefaultOptions = {
- iid: 1,
- 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,
- canPushToSourceBranch: true,
- emailPatchesPath: '/mr/email-patches',
- plainDiffPath: '/mr/plainDiffPath',
- statusPath: 'abc',
- sourceProjectFullPath: 'root/gitlab-ce',
- targetProjectFullPath: 'gitlab-org/gitlab-ce',
- };
-
- afterEach(() => {
- vm.$destroy();
- });
-
- beforeEach(() => {
- vm = mountComponent(Component, {
- mr: { ...mrDefaultOptions },
- });
- });
-
- 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 web ide button', () => {
- const button = vm.$el.querySelector('.js-web-ide');
-
- expect(button.textContent.trim()).toEqual('Open in Web IDE');
- expect(button.classList.contains('disabled')).toBe(false);
- expect(button.getAttribute('href')).toEqual(
- '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org%2Fgitlab-ce',
- );
- });
-
- it('renders web ide button in disabled state with no href', () => {
- const mr = { ...mrDefaultOptions, canPushToSourceBranch: false };
- vm = mountComponent(Component, { mr });
-
- const link = vm.$el.querySelector('.js-web-ide');
-
- expect(link.classList.contains('disabled')).toBe(true);
- expect(link.getAttribute('href')).toBeNull();
- });
-
- it('renders web ide button with blank query string if target & source project branch', done => {
- vm.mr.targetProjectFullPath = 'root/gitlab-ce';
-
- vm.$nextTick(() => {
- const button = vm.$el.querySelector('.js-web-ide');
-
- expect(button.textContent.trim()).toEqual('Open in Web IDE');
- expect(button.getAttribute('href')).toEqual(
- '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=',
- );
-
- done();
- });
- });
-
- it('renders web ide button with relative URL', done => {
- gon.relative_url_root = '/gitlab';
- vm.mr.iid = 2;
-
- vm.$nextTick(() => {
- const button = vm.$el.querySelector('.js-web-ide');
-
- expect(button.textContent.trim()).toEqual('Open in Web IDE');
- expect(button.getAttribute('href')).toEqual(
- '/gitlab/-/ide/project/root/gitlab-ce/merge_requests/2?target_project=gitlab-org%2Fgitlab-ce',
- );
-
- done();
- });
- });
-
- it('renders download dropdown with links', () => {
- expectDownloadDropdownItems();
- });
- });
-
- 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',
- statusPath: 'abc',
- },
- });
- });
-
- it('does not render checkout branch button with modal trigger', () => {
- const button = vm.$el.querySelector('.js-check-out-branch');
-
- expect(button).toEqual(null);
- });
-
- it('renders download dropdown with links', () => {
- expectDownloadDropdownItems();
- });
- });
-
- 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',
- statusPath: 'abc',
- },
- });
- });
-
- it('does not render diverged commits info', () => {
- expect(vm.$el.querySelector('.diverged-commits-count')).toEqual(null);
- });
- });
-
- 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',
- statusPath: 'abc',
- },
- });
- });
-
- it('renders diverged commits info', () => {
- expect(vm.$el.querySelector('.diverged-commits-count').textContent).toEqual(
- 'The source branch is 12 commits behind the target branch',
- );
-
- expect(vm.$el.querySelector('.diverged-commits-count a').textContent).toEqual(
- '12 commits behind',
- );
-
- expect(vm.$el.querySelector('.diverged-commits-count a')).toHaveAttr(
- 'href',
- vm.mr.targetBranchPath,
- );
- });
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
deleted file mode 100644
index d15c3552b4a..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
+++ /dev/null
@@ -1,223 +0,0 @@
-import Vue from 'vue';
-import MemoryUsage from '~/vue_merge_request_widget/components/deployment/memory_usage.vue';
-import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
-
-const url = '/root/acets-review-apps/environments/15/deployments/1/metrics';
-const monitoringUrl = '/root/acets-review-apps/environments/15/metrics';
-
-const metricsMockData = {
- success: true,
- metrics: {
- memory_before: [
- {
- metric: {},
- value: [1495785220.607, '9572875.906976745'],
- },
- ],
- memory_after: [
- {
- metric: {},
- value: [1495787020.607, '4485853.130206379'],
- },
- ],
- memory_values: [
- {
- metric: {},
- values: [[1493716685, '4.30859375']],
- },
- ],
- },
- last_update: '2017-05-02T12:34:49.628Z',
- deployment_time: 1493718485,
-};
-
-const createComponent = () => {
- const Component = Vue.extend(MemoryUsage);
-
- return new Component({
- el: document.createElement('div'),
- propsData: {
- metricsUrl: url,
- metricsMonitoringUrl: monitoringUrl,
- memoryMetrics: [],
- deploymentTime: 0,
- hasMetrics: false,
- loadFailed: false,
- loadingMetrics: true,
- backOffRequestCounter: 0,
- },
- });
-};
-
-const messages = {
- loadingMetrics: 'Loading deployment statistics',
- hasMetrics: 'Memory usage is unchanged at 0MB',
- loadFailed: 'Failed to load deployment statistics',
- metricsUnavailable: 'Deployment statistics are not available currently',
-};
-
-describe('MemoryUsage', () => {
- let vm;
- let el;
-
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
- });
-
- describe('data', () => {
- it('should have default data', () => {
- const data = MemoryUsage.data();
-
- expect(Array.isArray(data.memoryMetrics)).toBeTruthy();
- expect(data.memoryMetrics.length).toBe(0);
-
- expect(typeof data.deploymentTime).toBe('number');
- expect(data.deploymentTime).toBe(0);
-
- expect(typeof data.hasMetrics).toBe('boolean');
- expect(data.hasMetrics).toBeFalsy();
-
- expect(typeof data.loadFailed).toBe('boolean');
- expect(data.loadFailed).toBeFalsy();
-
- expect(typeof data.loadingMetrics).toBe('boolean');
- expect(data.loadingMetrics).toBeTruthy();
-
- expect(typeof data.backOffRequestCounter).toBe('number');
- expect(data.backOffRequestCounter).toBe(0);
- });
- });
-
- describe('computed', () => {
- describe('memoryChangeMessage', () => {
- it('should contain "increased" if memoryFrom value is less than memoryTo value', () => {
- vm.memoryFrom = 4.28;
- vm.memoryTo = 9.13;
-
- expect(vm.memoryChangeMessage.indexOf('increased')).not.toEqual('-1');
- });
-
- it('should contain "decreased" if memoryFrom value is less than memoryTo value', () => {
- vm.memoryFrom = 9.13;
- vm.memoryTo = 4.28;
-
- expect(vm.memoryChangeMessage.indexOf('decreased')).not.toEqual('-1');
- });
-
- it('should contain "unchanged" if memoryFrom value equal to memoryTo value', () => {
- vm.memoryFrom = 1;
- vm.memoryTo = 1;
-
- expect(vm.memoryChangeMessage.indexOf('unchanged')).not.toEqual('-1');
- });
- });
- });
-
- describe('methods', () => {
- const { metrics, deployment_time } = metricsMockData;
-
- describe('getMegabytes', () => {
- it('should return Megabytes from provided Bytes value', () => {
- const memoryInBytes = '9572875.906976745';
-
- expect(vm.getMegabytes(memoryInBytes)).toEqual('9.13');
- });
- });
-
- describe('computeGraphData', () => {
- it('should populate sparkline graph', () => {
- vm.computeGraphData(metrics, deployment_time);
- const { hasMetrics, memoryMetrics, deploymentTime, memoryFrom, memoryTo } = vm;
-
- expect(hasMetrics).toBeTruthy();
- expect(memoryMetrics.length).toBeGreaterThan(0);
- expect(deploymentTime).toEqual(deployment_time);
- expect(memoryFrom).toEqual('9.13');
- expect(memoryTo).toEqual('4.28');
- });
- });
-
- describe('loadMetrics', () => {
- const returnServicePromise = () =>
- new Promise(resolve => {
- resolve({
- data: metricsMockData,
- });
- });
-
- it('should load metrics data using MRWidgetService', done => {
- spyOn(MRWidgetService, 'fetchMetrics').and.returnValue(returnServicePromise(true));
- spyOn(vm, 'computeGraphData');
-
- vm.loadMetrics();
- setTimeout(() => {
- expect(MRWidgetService.fetchMetrics).toHaveBeenCalledWith(url);
- expect(vm.computeGraphData).toHaveBeenCalledWith(metrics, deployment_time);
- done();
- }, 333);
- });
- });
- });
-
- describe('template', () => {
- it('should render template elements correctly', () => {
- expect(el.classList.contains('mr-memory-usage')).toBeTruthy();
- expect(el.querySelector('.js-usage-info')).toBeDefined();
- });
-
- it('should show loading metrics message while metrics are being loaded', done => {
- vm.loadingMetrics = true;
- vm.hasMetrics = false;
- vm.loadFailed = false;
-
- Vue.nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-loading')).toBeDefined();
-
- expect(el.querySelector('.js-usage-info .usage-info-load-spinner')).toBeDefined();
-
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadingMetrics);
- done();
- });
- });
-
- it('should show deployment memory usage when metrics are loaded', done => {
- vm.loadingMetrics = false;
- vm.hasMetrics = true;
- vm.loadFailed = false;
- vm.memoryMetrics = metricsMockData.metrics.memory_values[0].values;
-
- Vue.nextTick(() => {
- expect(el.querySelector('.memory-graph-container')).toBeDefined();
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.hasMetrics);
- done();
- });
- });
-
- it('should show failure message when metrics loading failed', done => {
- vm.loadingMetrics = false;
- vm.hasMetrics = false;
- vm.loadFailed = true;
-
- Vue.nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-failed')).toBeDefined();
-
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.loadFailed);
- done();
- });
- });
-
- it('should show metrics unavailable message when metrics loading failed', done => {
- vm.loadingMetrics = false;
- vm.hasMetrics = false;
- vm.loadFailed = false;
-
- Vue.nextTick(() => {
- expect(el.querySelector('.js-usage-info.usage-info-unavailable')).toBeDefined();
-
- expect(el.querySelector('.js-usage-info').innerText).toContain(messages.metricsUnavailable);
- done();
- });
- });
- });
-});
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
deleted file mode 100644
index b566876fe1d..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_merge_help_spec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue';
-
-describe('MRWidgetMergeHelp', () => {
- let vm;
- let Component;
-
- beforeEach(() => {
- Component = Vue.extend(mergeHelpComponent);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('with missing branch', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- missingBranch: 'this-is-not-the-branch-you-are-looking-for',
- });
- });
-
- 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('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_pipeline_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
deleted file mode 100644
index 883c41085fa..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
+++ /dev/null
@@ -1,326 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { trimText } from 'spec/helpers/text_helper';
-import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
-import mockData from '../mock_data';
-
-describe('MRWidgetPipeline', () => {
- let vm;
- let Component;
-
- beforeEach(() => {
- Component = Vue.extend(pipelineComponent);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('computed', () => {
- describe('hasPipeline', () => {
- it('should return true when there is a pipeline', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- ciStatus: 'success',
- hasCi: true,
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.hasPipeline).toEqual(true);
- });
-
- it('should return false when there is no pipeline', () => {
- vm = mountComponent(Component, {
- pipeline: {},
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.hasPipeline).toEqual(false);
- });
- });
-
- describe('hasCIError', () => {
- it('should return false when there is no CI error', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.hasCIError).toEqual(false);
- });
-
- it('should return true when there is a CI error', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- hasCi: true,
- ciStatus: null,
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.hasCIError).toEqual(true);
- });
- });
-
- describe('coverageDeltaClass', () => {
- it('should return no class if there is no coverage change', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- pipelineCoverageDelta: '0',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.coverageDeltaClass).toEqual('');
- });
-
- it('should return text-success if the coverage increased', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- pipelineCoverageDelta: '10',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.coverageDeltaClass).toEqual('text-success');
- });
-
- it('should return text-danger if the coverage decreased', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- pipelineCoverageDelta: '-12',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.coverageDeltaClass).toEqual('text-danger');
- });
- });
- });
-
- describe('rendered output', () => {
- it('should render CI error', () => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- hasCi: true,
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
- 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.',
- );
- });
-
- it('should render CI error when no pipeline is provided', () => {
- vm = mountComponent(Component, {
- pipeline: {},
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
- 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.',
- );
- });
-
- it('should render CI error when no CI is provided and pipeline must succeed is turned on', () => {
- vm = mountComponent(Component, {
- pipeline: {},
- hasCi: false,
- pipelineMustSucceed: true,
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
- 'No pipeline has been run for this commit.',
- );
- });
-
- describe('with a pipeline', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- pipeline: mockData.pipeline,
- hasCi: true,
- ciStatus: 'success',
- pipelineCoverageDelta: mockData.pipelineCoverageDelta,
- troubleshootingDocsPath: 'help',
- });
- });
-
- it('should render pipeline ID', () => {
- expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual(
- `#${mockData.pipeline.id}`,
- );
- });
-
- it('should render pipeline status and commit id', () => {
- expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
- mockData.pipeline.details.status.label,
- );
-
- expect(vm.$el.querySelector('.js-commit-link').textContent.trim()).toEqual(
- mockData.pipeline.commit.short_id,
- );
-
- expect(vm.$el.querySelector('.js-commit-link').getAttribute('href')).toEqual(
- mockData.pipeline.commit.commit_path,
- );
- });
-
- it('should render pipeline graph', () => {
- expect(vm.$el.querySelector('.mr-widget-pipeline-graph')).toBeDefined();
- expect(vm.$el.querySelectorAll('.stage-container').length).toEqual(
- mockData.pipeline.details.stages.length,
- );
- });
-
- it('should render coverage information', () => {
- expect(vm.$el.querySelector('.media-body').textContent).toContain(
- `Coverage ${mockData.pipeline.coverage}`,
- );
- });
-
- it('should render pipeline coverage delta information', () => {
- expect(vm.$el.querySelector('.js-pipeline-coverage-delta.text-danger')).toBeDefined();
- expect(vm.$el.querySelector('.js-pipeline-coverage-delta').textContent).toContain(
- `(${mockData.pipelineCoverageDelta}%)`,
- );
- });
- });
-
- describe('without commit path', () => {
- beforeEach(() => {
- const mockCopy = JSON.parse(JSON.stringify(mockData));
- delete mockCopy.pipeline.commit;
-
- vm = mountComponent(Component, {
- pipeline: mockCopy.pipeline,
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- });
- });
-
- it('should render pipeline ID', () => {
- expect(vm.$el.querySelector('.pipeline-id').textContent.trim()).toEqual(
- `#${mockData.pipeline.id}`,
- );
- });
-
- it('should render pipeline status', () => {
- expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
- mockData.pipeline.details.status.label,
- );
-
- expect(vm.$el.querySelector('.js-commit-link')).toBeNull();
- });
-
- it('should render pipeline graph', () => {
- expect(vm.$el.querySelector('.mr-widget-pipeline-graph')).toBeDefined();
- expect(vm.$el.querySelectorAll('.stage-container').length).toEqual(
- mockData.pipeline.details.stages.length,
- );
- });
-
- it('should render coverage information', () => {
- expect(vm.$el.querySelector('.media-body').textContent).toContain(
- `Coverage ${mockData.pipeline.coverage}`,
- );
- });
- });
-
- describe('without coverage', () => {
- it('should not render a coverage', () => {
- const mockCopy = JSON.parse(JSON.stringify(mockData));
- delete mockCopy.pipeline.coverage;
-
- vm = mountComponent(Component, {
- pipeline: mockCopy.pipeline,
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.$el.querySelector('.media-body').textContent).not.toContain('Coverage');
- });
- });
-
- describe('without a pipeline graph', () => {
- it('should not render a pipeline graph', () => {
- const mockCopy = JSON.parse(JSON.stringify(mockData));
- delete mockCopy.pipeline.details.stages;
-
- vm = mountComponent(Component, {
- pipeline: mockCopy.pipeline,
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- });
-
- expect(vm.$el.querySelector('.js-mini-pipeline-graph')).toEqual(null);
- });
- });
-
- describe('for each type of pipeline', () => {
- let pipeline;
-
- beforeEach(() => {
- ({ pipeline } = JSON.parse(JSON.stringify(mockData)));
-
- pipeline.details.name = 'Pipeline';
- pipeline.merge_request_event_type = undefined;
- pipeline.ref.tag = false;
- pipeline.ref.branch = false;
- });
-
- const factory = () => {
- vm = mountComponent(Component, {
- pipeline,
- hasCi: true,
- ciStatus: 'success',
- troubleshootingDocsPath: 'help',
- sourceBranchLink: mockData.source_branch_link,
- });
- };
-
- describe('for a branch pipeline', () => {
- it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => {
- pipeline.ref.branch = true;
-
- factory();
-
- const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockData.source_branch_link}`;
- const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
-
- expect(actual).toBe(expected);
- });
- });
-
- describe('for a tag pipeline', () => {
- it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => {
- pipeline.ref.tag = true;
-
- factory();
-
- const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
- const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
-
- expect(actual).toBe(expected);
- });
- });
-
- describe('for a detached merge request pipeline', () => {
- it('renders a pipeline widget that reads "Detached merge request pipeline <ID> <status> for <SHA>"', () => {
- pipeline.details.name = 'Detached merge request pipeline';
- pipeline.merge_request_event_type = 'detached';
-
- factory();
-
- const expected = `Detached merge request pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`;
- const actual = trimText(vm.$el.querySelector('.js-pipeline-info-container').innerText);
-
- expect(actual).toBe(expected);
- });
- });
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
deleted file mode 100644
index 5b293862b16..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
-
-describe('Merge request widget rebase component', () => {
- let Component;
- let vm;
- beforeEach(() => {
- Component = Vue.extend(component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('While rebasing', () => {
- it('should show progress message', () => {
- vm = mountComponent(Component, {
- mr: { rebaseInProgress: true },
- service: {},
- });
-
- expect(
- vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
- ).toContain('Rebase in progress');
- });
- });
-
- describe('With permissions', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {},
- });
- });
-
- it('it should render rebase button and warning message', () => {
- const text = vm.$el
- .querySelector('.rebase-state-find-class-convention span')
- .textContent.trim();
-
- expect(text).toContain('Fast-forward merge is not possible.');
- expect(text.replace(/\s\s+/g, ' ')).toContain(
- 'Rebase the source branch onto the target branch or merge target',
- );
-
- expect(text).toContain('branch into source branch to allow this merge request to be merged.');
- });
-
- it('it should render error message when it fails', done => {
- vm.rebasingError = 'Something went wrong!';
-
- Vue.nextTick(() => {
- expect(
- vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
- ).toContain('Something went wrong!');
- done();
- });
- });
- });
-
- describe('Without permissions', () => {
- it('should render a message explaining user does not have permissions', () => {
- vm = mountComponent(Component, {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
- targetBranch: 'foo',
- },
- service: {},
- });
-
- const text = vm.$el
- .querySelector('.rebase-state-find-class-convention span')
- .textContent.trim();
-
- expect(text).toContain('Fast-forward merge is not possible.');
- expect(text).toContain('Rebase the source branch onto');
- expect(text).toContain('foo');
- expect(text.replace(/\s\s+/g, ' ')).toContain('to allow this merge request to be merged.');
- });
-
- it('should render the correct target branch name', () => {
- const targetBranch = 'fake-branch-to-test-with';
- vm = mountComponent(Component, {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
- targetBranch,
- },
- service: {},
- });
-
- const elem = vm.$el.querySelector('.rebase-state-find-class-convention span');
-
- expect(elem.innerHTML).toContain(
- `Fast-forward merge is not possible. Rebase the source branch onto <span class="label-branch">${targetBranch}</span> to allow this merge request to be merged.`,
- );
- });
- });
-
- describe('methods', () => {
- it('checkRebaseStatus', done => {
- spyOn(eventHub, '$emit');
- vm = mountComponent(Component, {
- mr: {},
- service: {
- rebase() {
- return Promise.resolve();
- },
- poll() {
- return Promise.resolve({
- data: {
- rebase_in_progress: false,
- merge_error: null,
- },
- });
- },
- },
- });
-
- vm.rebase();
-
- // Wait for the rebase request
- vm.$nextTick()
- // Wait for the polling request
- .then(vm.$nextTick())
- // Wait for the eventHub to be called
- .then(vm.$nextTick())
- .then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess');
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
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
deleted file mode 100644
index a152bd01916..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue';
-
-describe('MRWidgetRelatedLinks', () => {
- let vm;
-
- const createComponent = data => {
- const Component = Vue.extend(relatedLinksComponent);
-
- return mountComponent(Component, data);
- };
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('computed', () => {
- describe('closesText', () => {
- 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', () => {
- vm = createComponent({ state: 'closed', relatedLinks: {} });
-
- expect(vm.closesText).toEqual('Did not close');
- });
-
- it('returns correct tense for merged request', () => {
- vm = createComponent({ state: 'merged', relatedLinks: {} });
-
- expect(vm.closesText).toEqual('Closed');
- });
- });
- });
-
- 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();
-
- expect(content).toContain('Closes #23 and #42');
- expect(content).not.toContain('Mentions');
- });
-
- it('should have only have mentioned issues text', () => {
- vm = createComponent({
- relatedLinks: {
- mentioned: '<a href="#">#7</a>',
- },
- });
-
- expect(vm.$el.innerText).toContain('Mentions #7');
- expect(vm.$el.innerText).not.toContain('Closes');
- });
-
- 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();
-
- expect(content).toContain('Closes #7');
- expect(content).toContain('Mentions #23 and #42');
- });
-
- 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
deleted file mode 100644
index 20bda024d89..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import mrStatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
-
-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 span').classList).toContain('gl-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/review_app_link_spec.js b/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js
deleted file mode 100644
index 242193c7b3d..00000000000
--- a/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import Vue from 'vue';
-import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
-import component from '~/vue_merge_request_widget/components/review_app_link.vue';
-import mountComponent from '../../helpers/vue_mount_component_helper';
-
-describe('review app link', () => {
- const Component = Vue.extend(component);
- const props = {
- link: '/review',
- cssClass: 'js-link',
- display: {
- text: 'View app',
- tooltip: '',
- },
- };
- let vm;
- let el;
-
- beforeEach(() => {
- vm = mountComponent(Component, props);
- el = vm.$el;
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders provided link as href attribute', () => {
- expect(el.getAttribute('href')).toEqual(props.link);
- });
-
- it('renders provided cssClass as class attribute', () => {
- expect(el.getAttribute('class')).toEqual(props.cssClass);
- });
-
- it('renders View app text', () => {
- expect(el.textContent.trim()).toEqual('View app');
- });
-
- it('renders svg icon', () => {
- expect(el.querySelector('svg')).not.toBeNull();
- });
-
- it('tracks an event when clicked', () => {
- const spy = mockTracking('_category_', el, spyOn);
- triggerEvent(el);
-
- expect(spy).toHaveBeenCalledWith('_category_', 'open_review_app', {
- label: 'review_app',
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js
deleted file mode 100644
index 29a257b0e24..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import archivedComponent from '~/vue_merge_request_widget/components/states/mr_widget_archived.vue';
-
-describe('MRWidgetArchived', () => {
- let vm;
-
- beforeEach(() => {
- const Component = Vue.extend(archivedComponent);
- vm = mountComponent(Component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders a ci status failed icon', () => {
- expect(vm.$el.querySelector('.ci-status-icon')).not.toBeNull();
- });
-
- it('renders a disabled button', () => {
- expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled');
- expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Merge');
- });
-
- it('renders information', () => {
- expect(vm.$el.querySelector('.bold').textContent.trim()).toEqual(
- 'This project is archived, write access has been disabled',
- );
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js
deleted file mode 100644
index 73b65178ecf..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_enabled_spec.js
+++ /dev/null
@@ -1,230 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { trimText } from 'spec/helpers/text_helper';
-import autoMergeEnabledComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue';
-import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
-
-describe('MRWidgetAutoMergeEnabled', () => {
- let vm;
- const targetBranchPath = '/foo/bar';
- const targetBranch = 'foo';
- const sha = '1EA2EZ34';
-
- beforeEach(() => {
- const Component = Vue.extend(autoMergeEnabledComponent);
- spyOn(eventHub, '$emit');
-
- vm = mountComponent(Component, {
- mr: {
- shouldRemoveSourceBranch: false,
- canRemoveSourceBranch: true,
- canCancelAutomaticMerge: true,
- mergeUserId: 1,
- currentUserId: 1,
- setToAutoMergeBy: {},
- sha,
- targetBranchPath,
- targetBranch,
- autoMergeStrategy: MWPS_MERGE_STRATEGY,
- },
- service: new MRWidgetService({}),
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('computed', () => {
- describe('canRemoveSourceBranch', () => {
- it('should return true when user is able to remove source branch', () => {
- expect(vm.canRemoveSourceBranch).toBeTruthy();
- });
-
- it('should return false when user id is not the same with who set the MWPS', () => {
- vm.mr.mergeUserId = 2;
-
- expect(vm.canRemoveSourceBranch).toBeFalsy();
-
- vm.mr.currentUserId = 2;
-
- expect(vm.canRemoveSourceBranch).toBeTruthy();
-
- vm.mr.currentUserId = 3;
-
- expect(vm.canRemoveSourceBranch).toBeFalsy();
- });
-
- it('should return false when shouldRemoveSourceBranch set to false', () => {
- vm.mr.shouldRemoveSourceBranch = true;
-
- expect(vm.canRemoveSourceBranch).toBeFalsy();
- });
-
- it('should return false if user is not able to remove the source branch', () => {
- vm.mr.canRemoveSourceBranch = false;
-
- expect(vm.canRemoveSourceBranch).toBeFalsy();
- });
- });
-
- describe('statusTextBeforeAuthor', () => {
- it('should return "Set by" if the MWPS is selected', () => {
- Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- expect(vm.statusTextBeforeAuthor).toBe('Set by');
- });
- });
-
- describe('statusTextAfterAuthor', () => {
- it('should return "to be merged automatically..." if MWPS is selected', () => {
- Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- expect(vm.statusTextAfterAuthor).toBe(
- 'to be merged automatically when the pipeline succeeds',
- );
- });
- });
-
- describe('cancelButtonText', () => {
- it('should return "Cancel automatic merge" if MWPS is selected', () => {
- Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- expect(vm.cancelButtonText).toBe('Cancel automatic merge');
- });
- });
- });
-
- describe('methods', () => {
- describe('cancelAutomaticMerge', () => {
- it('should set flag and call service then tell main component to update the widget with data', done => {
- const mrObj = {
- is_new_mr_data: true,
- };
- spyOn(vm.service, 'cancelAutomaticMerge').and.returnValue(
- new Promise(resolve => {
- resolve({
- data: mrObj,
- });
- }),
- );
-
- vm.cancelAutomaticMerge();
- setTimeout(() => {
- expect(vm.isCancellingAutoMerge).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- done();
- }, 333);
- });
- });
-
- describe('removeSourceBranch', () => {
- it('should set flag and call service then request main component to update the widget', done => {
- spyOn(vm.service, 'merge').and.returnValue(
- Promise.resolve({
- data: {
- status: MWPS_MERGE_STRATEGY,
- },
- }),
- );
-
- vm.removeSourceBranch();
- setTimeout(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(vm.service.merge).toHaveBeenCalledWith({
- sha,
- auto_merge_strategy: MWPS_MERGE_STRATEGY,
- should_remove_source_branch: true,
- });
- done();
- }, 333);
- });
- });
- });
-
- describe('template', () => {
- it('should have correct elements', () => {
- 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 deleted');
- 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(
- 'Delete 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(vm.$el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeTruthy();
- done();
- });
- });
-
- it('should show source branch will be deleted text when it source branch set to remove', done => {
- vm.mr.shouldRemoveSourceBranch = true;
-
- Vue.nextTick(() => {
- const normalizedText = vm.$el.innerText.replace(/\s+/g, ' ');
-
- expect(normalizedText).toContain('The source branch will be deleted');
- expect(normalizedText).not.toContain('The source branch will not be deleted');
- done();
- });
- });
-
- it('should not show delete source branch button when user not able to delete source branch', done => {
- vm.mr.currentUserId = 4;
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.js-remove-source-branch')).toEqual(null);
- done();
- });
- });
-
- it('should disable delete source branch button when the action is in progress', done => {
- vm.isRemovingSourceBranch = true;
-
- Vue.nextTick(() => {
- expect(
- vm.$el.querySelector('.js-remove-source-branch').getAttribute('disabled'),
- ).toBeTruthy();
- done();
- });
- });
-
- it('should render the status text as "...to merged automatically" if MWPS is selected', done => {
- Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- Vue.nextTick(() => {
- const statusText = trimText(vm.$el.querySelector('.js-status-text-after-author').innerText);
-
- expect(statusText).toBe('to be merged automatically when the pipeline succeeds');
- done();
- });
- });
-
- it('should render the cancel button as "Cancel automatic merge" if MWPS is selected', done => {
- Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- Vue.nextTick(() => {
- const cancelButtonText = trimText(vm.$el.querySelector('.js-cancel-auto-merge').innerText);
-
- expect(cancelButtonText).toBe('Cancel automatic merge');
- done();
- });
- });
- });
-});
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
deleted file mode 100644
index efccd507fe2..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue';
-
-describe('MRWidgetChecking', () => {
- let Component;
- let vm;
-
- 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 span').classList).toContain('gl-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
deleted file mode 100644
index bbbaed0d2f5..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue';
-
-describe('MRWidgetClosed', () => {
- 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',
- },
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders warning icon', () => {
- expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull();
- });
-
- 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');
- });
-
- it('links to the user that closed the MR', () => {
- expect(vm.$el.querySelector('.author-link').getAttribute('href')).toEqual(
- 'http://localhost:3000/root',
- );
- });
-
- 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('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
deleted file mode 100644
index 9035bc6f65d..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ /dev/null
@@ -1,225 +0,0 @@
-import $ from 'jquery';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import { removeBreakLine } from 'spec/helpers/text_helper';
-import ConflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
-
-describe('MRWidgetConflicts', () => {
- let vm;
- const path = '/conflicts';
-
- function createComponent(propsData = {}) {
- const localVue = createLocalVue();
-
- vm = shallowMount(localVue.extend(ConflictsComponent), {
- propsData,
- });
- }
-
- beforeEach(() => {
- spyOn($.fn, 'popover').and.callThrough();
- });
-
- afterEach(() => {
- vm.destroy();
- });
-
- // There are two permissions we need to consider:
- //
- // 1. Is the user allowed to merge to the target branch?
- // 2. Is the user allowed to push to the source branch?
- //
- // This yields 4 possible permutations that we need to test, and
- // we test them below. A user who can push to the source
- // branch should be allowed to resolve conflicts. This is
- // consistent with what the backend does.
- describe('when allowed to merge but not allowed to push to source branch', () => {
- beforeEach(() => {
- createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: false,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('should tell you about conflicts without bothering other people', () => {
- expect(vm.text()).toContain('There are merge conflicts');
- expect(vm.text()).not.toContain('ask someone with write access');
- });
-
- it('should not allow you to resolve the conflicts', () => {
- expect(vm.text()).not.toContain('Resolve conflicts');
- });
-
- it('should have merge buttons', () => {
- const mergeLocallyButton = vm.find('.js-merge-locally-button');
-
- expect(mergeLocallyButton.text()).toContain('Merge locally');
- });
- });
-
- describe('when not allowed to merge but allowed to push to source branch', () => {
- beforeEach(() => {
- createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: true,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('should tell you about conflicts', () => {
- expect(vm.text()).toContain('There are merge conflicts');
- expect(vm.text()).toContain('ask someone with write access');
- });
-
- it('should allow you to resolve the conflicts', () => {
- const resolveButton = vm.find('.js-resolve-conflicts-button');
-
- expect(resolveButton.text()).toContain('Resolve conflicts');
- expect(resolveButton.attributes('href')).toEqual(path);
- });
-
- it('should not have merge buttons', () => {
- expect(vm.text()).not.toContain('Merge locally');
- });
- });
-
- describe('when allowed to merge and push to source branch', () => {
- beforeEach(() => {
- createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('should tell you about conflicts without bothering other people', () => {
- expect(vm.text()).toContain('There are merge conflicts');
- expect(vm.text()).not.toContain('ask someone with write access');
- });
-
- it('should allow you to resolve the conflicts', () => {
- const resolveButton = vm.find('.js-resolve-conflicts-button');
-
- expect(resolveButton.text()).toContain('Resolve conflicts');
- expect(resolveButton.attributes('href')).toEqual(path);
- });
-
- it('should have merge buttons', () => {
- const mergeLocallyButton = vm.find('.js-merge-locally-button');
-
- expect(mergeLocallyButton.text()).toContain('Merge locally');
- });
- });
-
- describe('when user does not have permission to push to source branch', () => {
- it('should show proper message', () => {
- createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: false,
- conflictsDocsPath: '',
- },
- });
-
- expect(
- vm
- .text()
- .trim()
- .replace(/\s\s+/g, ' '),
- ).toContain('ask someone with write access');
- });
-
- it('should not have action buttons', () => {
- createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: false,
- conflictsDocsPath: '',
- },
- });
-
- expect(vm.contains('.js-resolve-conflicts-button')).toBe(false);
- expect(vm.contains('.js-merge-locally-button')).toBe(false);
- });
-
- it('should not have resolve button when no conflict resolution path', () => {
- createComponent({
- mr: {
- canMerge: true,
- conflictResolutionPath: null,
- conflictsDocsPath: '',
- },
- });
-
- expect(vm.contains('.js-resolve-conflicts-button')).toBe(false);
- });
- });
-
- describe('when fast-forward or semi-linear merge enabled', () => {
- it('should tell you to rebase locally', () => {
- createComponent({
- mr: {
- shouldBeRebased: true,
- conflictsDocsPath: '',
- },
- });
-
- expect(removeBreakLine(vm.text()).trim()).toContain(
- 'Fast-forward merge is not possible. To merge this request, first rebase locally.',
- );
- });
- });
-
- describe('when source branch protected', () => {
- beforeEach(() => {
- createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: gl.TEST_HOST,
- sourceBranchProtected: true,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('sets resolve button as disabled', () => {
- expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe('disabled');
- });
-
- it('renders popover', () => {
- expect($.fn.popover).toHaveBeenCalled();
- });
- });
-
- describe('when source branch not protected', () => {
- beforeEach(() => {
- createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: gl.TEST_HOST,
- sourceBranchProtected: false,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('sets resolve button as disabled', () => {
- expect(vm.find('.js-resolve-conflicts-button').attributes('disabled')).toBe(undefined);
- });
-
- it('renders popover', () => {
- expect($.fn.popover).not.toHaveBeenCalled();
- });
- });
-});
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
deleted file mode 100644
index ef76e617c07..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-
-describe('MRWidgetFailedToMerge', () => {
- const dummyIntervalId = 1337;
- let Component;
- let mr;
- let vm;
-
- beforeEach(() => {
- Component = Vue.extend(failedToMergeComponent);
- spyOn(eventHub, '$emit');
- spyOn(window, 'setInterval').and.returnValue(dummyIntervalId);
- spyOn(window, 'clearInterval').and.stub();
- mr = {
- mergeError: 'Merge error happened',
- };
- vm = mountComponent(Component, {
- mr,
- });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('sets interval to refresh', () => {
- expect(window.setInterval).toHaveBeenCalledWith(vm.updateTimer, 1000);
- expect(vm.intervalId).toBe(dummyIntervalId);
- });
-
- it('clears interval when destroying ', () => {
- vm.$destroy();
-
- expect(window.clearInterval).toHaveBeenCalledWith(dummyIntervalId);
- });
-
- describe('computed', () => {
- describe('timerText', () => {
- it('should return correct timer text', () => {
- expect(vm.timerText).toEqual('Refreshing in 10 seconds to show the updated status...');
-
- vm.timer = 1;
-
- expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...');
- });
- });
-
- describe('mergeError', () => {
- it('removes forced line breaks', done => {
- mr.mergeError = 'contains<br />line breaks<br />';
-
- Vue.nextTick()
- .then(() => {
- expect(vm.mergeError).toBe('contains line breaks');
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
-
- describe('created', () => {
- it('should disable polling', () => {
- expect(eventHub.$emit).toHaveBeenCalledWith('DisablePolling');
- });
- });
-
- describe('methods', () => {
- describe('refresh', () => {
- it('should emit event to request component refresh', () => {
- expect(vm.isRefreshing).toEqual(false);
-
- vm.refresh();
-
- expect(vm.isRefreshing).toEqual(true);
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(eventHub.$emit).toHaveBeenCalledWith('EnablePolling');
- });
- });
-
- describe('updateTimer', () => {
- it('should update timer and emit event when timer end', () => {
- spyOn(vm, 'refresh');
-
- expect(vm.timer).toEqual(10);
-
- for (let i = 0; i < 10; i += 1) {
- expect(vm.timer).toEqual(10 - i);
- vm.updateTimer();
- }
-
- expect(vm.refresh).toHaveBeenCalled();
- });
- });
- });
-
- describe('while it is refreshing', () => {
- it('renders Refresing now', done => {
- vm.isRefreshing = true;
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.js-refresh-label').textContent.trim()).toEqual(
- 'Refreshing now',
- );
- done();
- });
- });
- });
-
- 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('renders refresh button', () => {
- expect(vm.$el.querySelector('.js-refresh-button').textContent.trim()).toEqual('Refresh now');
- });
-
- 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', 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_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
deleted file mode 100644
index 423c800bfbc..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ /dev/null
@@ -1,219 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-
-describe('MRWidgetMerged', () => {
- let vm;
- const targetBranch = 'foo';
- const selectors = {
- get copyMergeShaButton() {
- return vm.$el.querySelector('button.js-mr-merged-copy-sha');
- },
- get mergeCommitShaLink() {
- return vm.$el.querySelector('a.js-mr-merged-commit-sha');
- },
- };
-
- 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',
- shortMergeCommitSha: '958c0475',
- mergeCommitSha: '958c047516e182dfc52317f721f696e8a1ee85ed',
- mergeCommitPath:
- 'http://localhost:3000/root/nautilus/commit/f7ce827c314c9340b075657fd61c789fb01cf74d',
- sourceBranch: 'bar',
- targetBranch,
- };
-
- const service = {
- removeSourceBranch() {},
- };
-
- spyOn(eventHub, '$emit');
-
- vm = mountComponent(Component, { mr, service });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('computed', () => {
- describe('shouldShowRemoveSourceBranch', () => {
- it('returns true when sourceBranchRemoved is false', () => {
- vm.mr.sourceBranchRemoved = false;
-
- expect(vm.shouldShowRemoveSourceBranch).toEqual(true);
- });
-
- it('returns false when sourceBranchRemoved is true', () => {
- vm.mr.sourceBranchRemoved = true;
-
- expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
- });
-
- it('returns false when canRemoveSourceBranch is false', () => {
- vm.mr.sourceBranchRemoved = false;
- vm.mr.canRemoveSourceBranch = false;
-
- expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
- });
-
- it('returns false when is making request', () => {
- vm.mr.canRemoveSourceBranch = true;
- vm.isMakingRequest = true;
-
- 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).toEqual(false);
- });
- });
-
- describe('shouldShowSourceBranchRemoving', () => {
- it('should correct value when fields changed', () => {
- vm.mr.sourceBranchRemoved = false;
-
- expect(vm.shouldShowSourceBranchRemoving).toEqual(false);
-
- vm.mr.sourceBranchRemoved = true;
-
- expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
-
- vm.mr.sourceBranchRemoved = false;
- vm.isMakingRequest = true;
-
- expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
-
- vm.isMakingRequest = false;
- vm.mr.isRemovingSourceBranch = true;
-
- expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
- });
- });
- });
-
- describe('methods', () => {
- describe('removeSourceBranch', () => {
- it('should set flag and call service then request main component to update the widget', done => {
- spyOn(vm.service, 'removeSourceBranch').and.returnValue(
- new Promise(resolve => {
- resolve({
- data: {
- message: 'Branch was deleted',
- },
- });
- }),
- );
-
- vm.removeSourceBranch();
- setTimeout(() => {
- const args = eventHub.$emit.calls.argsFor(0);
-
- expect(vm.isMakingRequest).toEqual(true);
- expect(args[0]).toEqual('MRWidgetUpdateRequested');
- expect(args[1]).not.toThrow();
- done();
- }, 333);
- });
- });
- });
-
- it('has merged by information', () => {
- expect(vm.$el.textContent).toContain('Merged by');
- expect(vm.$el.textContent).toContain('Administrator');
- });
-
- it('renders branch information', () => {
- expect(vm.$el.textContent).toContain('The changes were merged into');
- expect(vm.$el.textContent).toContain(targetBranch);
- });
-
- it('renders information about branch being deleted', () => {
- expect(vm.$el.textContent).toContain('The source branch has been deleted');
- });
-
- it('shows revert and cherry-pick buttons', () => {
- expect(vm.$el.textContent).toContain('Revert');
- expect(vm.$el.textContent).toContain('Cherry-pick');
- });
-
- it('shows button to copy commit SHA to clipboard', () => {
- expect(selectors.copyMergeShaButton).toExist();
- expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe(
- vm.mr.mergeCommitSha,
- );
- });
-
- it('hides button to copy commit SHA if SHA does not exist', done => {
- vm.mr.mergeCommitSha = null;
-
- Vue.nextTick(() => {
- expect(selectors.copyMergeShaButton).not.toExist();
- expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
- done();
- });
- });
-
- it('shows merge commit SHA link', () => {
- expect(selectors.mergeCommitShaLink).toExist();
- expect(selectors.mergeCommitShaLink.text).toContain(vm.mr.shortMergeCommitSha);
- expect(selectors.mergeCommitShaLink.href).toBe(vm.mr.mergeCommitPath);
- });
-
- it('should not show source branch deleted text', done => {
- vm.mr.sourceBranchRemoved = false;
-
- Vue.nextTick(() => {
- expect(vm.$el.innerText).toContain('You can delete the source branch now');
- expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
- done();
- });
- });
-
- it('should show source branch deleting text', done => {
- vm.mr.isRemovingSourceBranch = true;
- vm.mr.sourceBranchRemoved = false;
-
- Vue.nextTick(() => {
- expect(vm.$el.innerText).toContain('The source branch is being deleted');
- expect(vm.$el.innerText).not.toContain('You can delete the source branch now');
- expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
- done();
- });
- });
-
- it('should use mergedEvent mergedAt as tooltip title', () => {
- expect(vm.$el.querySelector('time').getAttribute('data-original-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
deleted file mode 100644
index 06d236064dd..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merging_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue';
-
-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/components/states/mr_widget_missing_branch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
deleted file mode 100644
index 47b989e2022..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue';
-
-describe('MRWidgetMissingBranch', () => {
- let vm;
-
- beforeEach(() => {
- const Component = Vue.extend(missingBranchComponent);
- vm = mountComponent(Component, { mr: { sourceBranchRemoved: true } });
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('computed', () => {
- describe('missingBranchName', () => {
- it('should return proper branch name', () => {
- expect(vm.missingBranchName).toEqual('source');
-
- vm.mr.sourceBranchRemoved = false;
-
- expect(vm.missingBranchName).toEqual('target');
- });
- });
- });
-
- describe('template', () => {
- it('should have correct elements', () => {
- const el = vm.$el;
- const content = el.textContent.replace(/\n(\s)+/g, ' ').trim();
-
- expect(el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy();
- expect(content.replace(/\s\s+/g, ' ')).toContain('source branch does not exist.');
- expect(content).toContain('Please restore it or use a different source branch');
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js
deleted file mode 100644
index b1cb91663c9..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import notAllowedComponent from '~/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue';
-
-describe('MRWidgetNotAllowed', () => {
- let vm;
- beforeEach(() => {
- const Component = Vue.extend(notAllowedComponent);
- vm = mountComponent(Component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders success icon', () => {
- expect(vm.$el.querySelector('.ci-status-icon-success')).not.toBe(null);
- });
-
- it('renders informative text', () => {
- expect(vm.$el.innerText).toContain('Ready to be merged automatically.');
- expect(vm.$el.innerText).toContain(
- 'Ask someone with write access to this repository to merge this request',
- );
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
deleted file mode 100644
index bd0bd36ebc2..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_nothing_to_merge_spec.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import Vue from 'vue';
-import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing_to_merge.vue';
-
-describe('NothingToMerge', () => {
- describe('template', () => {
- const Component = Vue.extend(NothingToMerge);
- const newBlobPath = '/foo';
- const vm = new Component({
- el: document.createElement('div'),
- propsData: {
- mr: { newBlobPath },
- },
- });
-
- it('should have correct elements', () => {
- expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(vm.$el.querySelector('a').href).toContain(newBlobPath);
- expect(vm.$el.innerText).toContain(
- "Currently there are no changes in this merge request's source branch",
- );
-
- expect(vm.$el.innerText.replace(/\s\s+/g, ' ')).toContain(
- 'Please push new commits or use a different branch.',
- );
- });
-
- it('should not show new blob link if there is no link available', () => {
- vm.mr.newBlobPath = null;
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('a')).toEqual(null);
- });
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js
deleted file mode 100644
index 0bca86b12b2..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { removeBreakLine } from 'spec/helpers/text_helper';
-import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
-
-describe('MRWidgetPipelineBlocked', () => {
- let vm;
- beforeEach(() => {
- const Component = Vue.extend(pipelineBlockedComponent);
- vm = mountComponent(Component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders warning icon', () => {
- expect(vm.$el.querySelector('.ci-status-icon-warning')).not.toBe(null);
- });
-
- it('renders information text', () => {
- expect(removeBreakLine(vm.$el.textContent).trim()).toContain(
- 'Pipeline blocked. The pipeline for this merge request requires a manual action to proceed',
- );
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js
deleted file mode 100644
index 85f65d024a8..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Vue from 'vue';
-import { removeBreakLine } from 'spec/helpers/text_helper';
-import PipelineFailed from '~/vue_merge_request_widget/components/states/pipeline_failed.vue';
-
-describe('PipelineFailed', () => {
- describe('template', () => {
- const Component = Vue.extend(PipelineFailed);
- const vm = new Component({
- el: document.createElement('div'),
- });
- it('should have correct elements', () => {
- expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
- expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy();
- expect(removeBreakLine(vm.$el.innerText).trim()).toContain(
- 'The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure',
- );
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
deleted file mode 100644
index 9ba429c3d20..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ /dev/null
@@ -1,983 +0,0 @@
-import Vue from 'vue';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue';
-import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
-import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue';
-import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue';
-import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-import { MWPS_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
-
-const commitMessage = 'This is the commit message';
-const squashCommitMessage = 'This is the squash commit message';
-const commitMessageWithDescription = 'This is the commit message description';
-const createTestMr = customConfig => {
- const mr = {
- isPipelineActive: false,
- pipeline: null,
- isPipelineFailed: false,
- isPipelinePassing: false,
- isMergeAllowed: true,
- isApproved: true,
- onlyAllowMergeIfPipelineSucceeds: false,
- ffOnlyEnabled: false,
- hasCI: false,
- ciStatus: null,
- sha: '12345678',
- squash: false,
- commitMessage,
- squashCommitMessage,
- commitMessageWithDescription,
- shouldRemoveSourceBranch: true,
- canRemoveSourceBranch: false,
- targetBranch: 'master',
- preferredAutoMergeStrategy: MWPS_MERGE_STRATEGY,
- availableAutoMergeStrategies: [MWPS_MERGE_STRATEGY],
- };
-
- Object.assign(mr, customConfig.mr);
-
- return mr;
-};
-
-const createTestService = () => ({
- merge() {},
- poll() {},
-});
-
-const createComponent = (customConfig = {}) => {
- const Component = Vue.extend(ReadyToMerge);
-
- return new Component({
- el: document.createElement('div'),
- propsData: {
- mr: createTestMr(customConfig),
- service: createTestService(),
- },
- });
-};
-
-describe('ReadyToMerge', () => {
- let vm;
- let updateMrCountSpy;
-
- beforeEach(() => {
- vm = createComponent();
- updateMrCountSpy = spyOnDependency(ReadyToMerge, 'refreshUserMergeRequestCounts');
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('props', () => {
- it('should have props', () => {
- const { mr, service } = ReadyToMerge.props;
-
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
-
- expect(service.type instanceof Object).toBeTruthy();
- expect(service.required).toBeTruthy();
- });
- });
-
- describe('data', () => {
- it('should have default data', () => {
- expect(vm.mergeWhenBuildSucceeds).toBeFalsy();
- expect(vm.useCommitMessageWithDescription).toBeFalsy();
- expect(vm.showCommitMessageEditor).toBeFalsy();
- expect(vm.isMakingRequest).toBeFalsy();
- expect(vm.isMergingImmediately).toBeFalsy();
- expect(vm.commitMessage).toBe(vm.mr.commitMessage);
- expect(vm.successSvg).toBeDefined();
- expect(vm.warningSvg).toBeDefined();
- });
- });
-
- describe('computed', () => {
- describe('isAutoMergeAvailable', () => {
- it('should return true when at least one merge strategy is available', () => {
- vm.mr.availableAutoMergeStrategies = [MWPS_MERGE_STRATEGY];
-
- expect(vm.isAutoMergeAvailable).toBe(true);
- });
-
- it('should return false when no merge strategies are available', () => {
- vm.mr.availableAutoMergeStrategies = [];
-
- expect(vm.isAutoMergeAvailable).toBe(false);
- });
- });
-
- describe('status', () => {
- it('defaults to success', () => {
- Vue.set(vm.mr, 'pipeline', true);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.status).toEqual('success');
- });
-
- it('returns failed when MR has CI but also has an unknown status', () => {
- Vue.set(vm.mr, 'hasCI', true);
-
- expect(vm.status).toEqual('failed');
- });
-
- it('returns default when MR has no pipeline', () => {
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.status).toEqual('success');
- });
-
- it('returns pending when pipeline is active', () => {
- Vue.set(vm.mr, 'pipeline', {});
- Vue.set(vm.mr, 'isPipelineActive', true);
-
- expect(vm.status).toEqual('pending');
- });
-
- it('returns failed when pipeline is failed', () => {
- Vue.set(vm.mr, 'pipeline', {});
- Vue.set(vm.mr, 'isPipelineFailed', true);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.status).toEqual('failed');
- });
- });
-
- describe('mergeButtonVariant', () => {
- it('defaults to success class', () => {
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.mergeButtonVariant).toEqual('success');
- });
-
- it('returns success class for success status', () => {
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
- Vue.set(vm.mr, 'pipeline', true);
-
- expect(vm.mergeButtonVariant).toEqual('success');
- });
-
- it('returns info class for pending status', () => {
- Vue.set(vm.mr, 'availableAutoMergeStrategies', [MTWPS_MERGE_STRATEGY]);
-
- expect(vm.mergeButtonVariant).toEqual('info');
- });
-
- it('returns danger class for failed status', () => {
- vm.mr.hasCI = true;
-
- expect(vm.mergeButtonVariant).toEqual('danger');
- });
- });
-
- describe('status icon', () => {
- it('defaults to tick icon', () => {
- expect(vm.iconClass).toEqual('success');
- });
-
- it('shows tick for success status', () => {
- vm.mr.pipeline = true;
-
- expect(vm.iconClass).toEqual('success');
- });
-
- it('shows tick for pending status', () => {
- vm.mr.pipeline = {};
- vm.mr.isPipelineActive = true;
-
- expect(vm.iconClass).toEqual('success');
- });
-
- it('shows warning icon for failed status', () => {
- vm.mr.hasCI = true;
-
- expect(vm.iconClass).toEqual('warning');
- });
-
- it('shows warning icon for merge not allowed', () => {
- vm.mr.hasCI = true;
-
- expect(vm.iconClass).toEqual('warning');
- });
- });
-
- describe('mergeButtonText', () => {
- it('should return "Merge" when no auto merge strategies are available', () => {
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.mergeButtonText).toEqual('Merge');
- });
-
- it('should return "Merge in progress"', () => {
- Vue.set(vm, 'isMergingImmediately', true);
-
- expect(vm.mergeButtonText).toEqual('Merge in progress');
- });
-
- it('should return "Merge when pipeline succeeds" when the MWPS auto merge strategy is available', () => {
- Vue.set(vm, 'isMergingImmediately', false);
- Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- expect(vm.mergeButtonText).toEqual('Merge when pipeline succeeds');
- });
- });
-
- describe('autoMergeText', () => {
- it('should return Merge when pipeline succeeds', () => {
- Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY);
-
- expect(vm.autoMergeText).toEqual('Merge when pipeline succeeds');
- });
- });
-
- describe('shouldShowMergeImmediatelyDropdown', () => {
- it('should return false if no pipeline is active', () => {
- Vue.set(vm.mr, 'isPipelineActive', false);
- Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', false);
-
- expect(vm.shouldShowMergeImmediatelyDropdown).toBe(false);
- });
-
- it('should return false if "Pipelines must succeed" is enabled for the current project', () => {
- Vue.set(vm.mr, 'isPipelineActive', true);
- Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true);
-
- expect(vm.shouldShowMergeImmediatelyDropdown).toBe(false);
- });
-
- it('should return true if the MR\'s pipeline is active and "Pipelines must succeed" is not enabled for the current project', () => {
- Vue.set(vm.mr, 'isPipelineActive', true);
- Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', false);
-
- expect(vm.shouldShowMergeImmediatelyDropdown).toBe(true);
- });
- });
-
- describe('isMergeButtonDisabled', () => {
- it('should return false with initial data', () => {
- Vue.set(vm.mr, 'isMergeAllowed', true);
-
- expect(vm.isMergeButtonDisabled).toBe(false);
- });
-
- it('should return true when there is no commit message', () => {
- Vue.set(vm.mr, 'isMergeAllowed', true);
- Vue.set(vm, 'commitMessage', '');
-
- expect(vm.isMergeButtonDisabled).toBe(true);
- });
-
- it('should return true if merge is not allowed', () => {
- Vue.set(vm.mr, 'isMergeAllowed', false);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
- Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true);
-
- expect(vm.isMergeButtonDisabled).toBe(true);
- });
-
- it('should return true when the vm instance is making request', () => {
- Vue.set(vm.mr, 'isMergeAllowed', true);
- Vue.set(vm, 'isMakingRequest', true);
-
- expect(vm.isMergeButtonDisabled).toBe(true);
- });
- });
-
- describe('isMergeImmediatelyDangerous', () => {
- it('should always return false in CE', () => {
- expect(vm.isMergeImmediatelyDangerous).toBe(false);
- });
- });
- });
-
- describe('methods', () => {
- describe('shouldShowMergeControls', () => {
- it('should return false when an external pipeline is running and required to succeed', () => {
- Vue.set(vm.mr, 'isMergeAllowed', false);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.shouldShowMergeControls).toBe(false);
- });
-
- it('should return true when the build succeeded or build not required to succeed', () => {
- Vue.set(vm.mr, 'isMergeAllowed', true);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
-
- expect(vm.shouldShowMergeControls).toBe(true);
- });
-
- it('should return true when showing the MWPS button and a pipeline is running that needs to be successful', () => {
- Vue.set(vm.mr, 'isMergeAllowed', false);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]);
-
- expect(vm.shouldShowMergeControls).toBe(true);
- });
-
- it('should return true when showing the MWPS button but not required for the pipeline to succeed', () => {
- Vue.set(vm.mr, 'isMergeAllowed', true);
- Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]);
-
- expect(vm.shouldShowMergeControls).toBe(true);
- });
- });
-
- describe('updateMergeCommitMessage', () => {
- it('should revert flag and change commitMessage', () => {
- expect(vm.commitMessage).toEqual(commitMessage);
- vm.updateMergeCommitMessage(true);
-
- expect(vm.commitMessage).toEqual(commitMessageWithDescription);
- vm.updateMergeCommitMessage(false);
-
- expect(vm.commitMessage).toEqual(commitMessage);
- });
- });
-
- describe('handleMergeButtonClick', () => {
- const returnPromise = status =>
- new Promise(resolve => {
- resolve({
- data: {
- status,
- },
- });
- });
-
- it('should handle merge when pipeline succeeds', done => {
- spyOn(eventHub, '$emit');
- spyOn(vm.service, 'merge').and.returnValue(returnPromise('merge_when_pipeline_succeeds'));
- vm.removeSourceBranch = false;
- vm.handleMergeButtonClick(true);
-
- setTimeout(() => {
- expect(vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
-
- const params = vm.service.merge.calls.argsFor(0)[0];
-
- expect(params).toEqual(
- jasmine.objectContaining({
- sha: vm.mr.sha,
- commit_message: vm.mr.commitMessage,
- should_remove_source_branch: false,
- auto_merge_strategy: 'merge_when_pipeline_succeeds',
- }),
- );
- done();
- }, 333);
- });
-
- it('should handle merge failed', done => {
- spyOn(eventHub, '$emit');
- spyOn(vm.service, 'merge').and.returnValue(returnPromise('failed'));
- vm.handleMergeButtonClick(false, true);
-
- setTimeout(() => {
- expect(vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
-
- const params = vm.service.merge.calls.argsFor(0)[0];
-
- expect(params.should_remove_source_branch).toBeTruthy();
- expect(params.auto_merge_strategy).toBeUndefined();
- done();
- }, 333);
- });
-
- it('should handle merge action accepted case', done => {
- spyOn(vm.service, 'merge').and.returnValue(returnPromise('success'));
- spyOn(vm, 'initiateMergePolling');
- vm.handleMergeButtonClick();
-
- setTimeout(() => {
- expect(vm.isMakingRequest).toBeTruthy();
- expect(vm.initiateMergePolling).toHaveBeenCalled();
-
- const params = vm.service.merge.calls.argsFor(0)[0];
-
- expect(params.should_remove_source_branch).toBeTruthy();
- expect(params.auto_merge_strategy).toBeUndefined();
- done();
- }, 333);
- });
- });
-
- describe('initiateMergePolling', () => {
- beforeEach(() => {
- jasmine.clock().install();
- });
-
- afterEach(() => {
- jasmine.clock().uninstall();
- });
-
- it('should call simplePoll', () => {
- const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll');
- vm.initiateMergePolling();
-
- expect(simplePoll).toHaveBeenCalledWith(jasmine.any(Function), { timeout: 0 });
- });
-
- it('should call handleMergePolling', () => {
- spyOn(vm, 'handleMergePolling');
-
- vm.initiateMergePolling();
-
- jasmine.clock().tick(2000);
-
- expect(vm.handleMergePolling).toHaveBeenCalled();
- });
- });
-
- describe('handleMergePolling', () => {
- const returnPromise = state =>
- new Promise(resolve => {
- resolve({
- data: {
- state,
- source_branch_exists: true,
- },
- });
- });
-
- beforeEach(() => {
- loadFixtures('merge_requests/merge_request_of_current_user.html');
- });
-
- it('should call start and stop polling when MR merged', done => {
- spyOn(eventHub, '$emit');
- spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged'));
- spyOn(vm, 'initiateRemoveSourceBranchPolling');
-
- let cpc = false; // continuePollingCalled
- let spc = false; // stopPollingCalled
-
- vm.handleMergePolling(
- () => {
- cpc = true;
- },
- () => {
- spc = true;
- },
- );
- setTimeout(() => {
- expect(vm.service.poll).toHaveBeenCalled();
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(eventHub.$emit).toHaveBeenCalledWith('FetchActionsContent');
- expect(vm.initiateRemoveSourceBranchPolling).toHaveBeenCalled();
- expect(updateMrCountSpy).toHaveBeenCalled();
- expect(cpc).toBeFalsy();
- expect(spc).toBeTruthy();
-
- done();
- }, 333);
- });
-
- it('updates status box', done => {
- spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged'));
- spyOn(vm, 'initiateRemoveSourceBranchPolling');
-
- vm.handleMergePolling(() => {}, () => {});
-
- setTimeout(() => {
- const statusBox = document.querySelector('.status-box');
-
- expect(statusBox.classList.contains('status-box-mr-merged')).toBeTruthy();
- expect(statusBox.textContent).toContain('Merged');
-
- done();
- });
- });
-
- it('hides close button', done => {
- spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged'));
- spyOn(vm, 'initiateRemoveSourceBranchPolling');
-
- vm.handleMergePolling(() => {}, () => {});
-
- setTimeout(() => {
- expect(document.querySelector('.btn-close').classList.contains('hidden')).toBeTruthy();
-
- done();
- });
- });
-
- it('updates merge request count badge', done => {
- spyOn(vm.service, 'poll').and.returnValue(returnPromise('merged'));
- spyOn(vm, 'initiateRemoveSourceBranchPolling');
-
- vm.handleMergePolling(() => {}, () => {});
-
- setTimeout(() => {
- expect(document.querySelector('.js-merge-counter').textContent).toBe('0');
-
- done();
- });
- });
-
- it('should continue polling until MR is merged', done => {
- spyOn(vm.service, 'poll').and.returnValue(returnPromise('some_other_state'));
- spyOn(vm, 'initiateRemoveSourceBranchPolling');
-
- let cpc = false; // continuePollingCalled
- let spc = false; // stopPollingCalled
-
- vm.handleMergePolling(
- () => {
- cpc = true;
- },
- () => {
- spc = true;
- },
- );
- setTimeout(() => {
- expect(cpc).toBeTruthy();
- expect(spc).toBeFalsy();
-
- done();
- }, 333);
- });
- });
-
- describe('initiateRemoveSourceBranchPolling', () => {
- it('should emit event and call simplePoll', () => {
- spyOn(eventHub, '$emit');
- const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll');
-
- vm.initiateRemoveSourceBranchPolling();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [true]);
- expect(simplePoll).toHaveBeenCalled();
- });
- });
-
- describe('handleRemoveBranchPolling', () => {
- const returnPromise = state =>
- new Promise(resolve => {
- resolve({
- data: {
- source_branch_exists: state,
- },
- });
- });
-
- it('should call start and stop polling when MR merged', done => {
- spyOn(eventHub, '$emit');
- spyOn(vm.service, 'poll').and.returnValue(returnPromise(false));
-
- let cpc = false; // continuePollingCalled
- let spc = false; // stopPollingCalled
-
- vm.handleRemoveBranchPolling(
- () => {
- cpc = true;
- },
- () => {
- spc = true;
- },
- );
- setTimeout(() => {
- expect(vm.service.poll).toHaveBeenCalled();
-
- const args = eventHub.$emit.calls.argsFor(0);
-
- expect(args[0]).toEqual('MRWidgetUpdateRequested');
- expect(args[1]).toBeDefined();
- args[1]();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]);
-
- expect(cpc).toBeFalsy();
- expect(spc).toBeTruthy();
-
- done();
- }, 333);
- });
-
- it('should continue polling until MR is merged', done => {
- spyOn(vm.service, 'poll').and.returnValue(returnPromise(true));
-
- let cpc = false; // continuePollingCalled
- let spc = false; // stopPollingCalled
-
- vm.handleRemoveBranchPolling(
- () => {
- cpc = true;
- },
- () => {
- spc = true;
- },
- );
- setTimeout(() => {
- expect(cpc).toBeTruthy();
- expect(spc).toBeFalsy();
-
- done();
- }, 333);
- });
- });
- });
-
- describe('Remove source branch checkbox', () => {
- describe('when user can merge but cannot delete branch', () => {
- it('should be disabled in the rendered output', () => {
- const checkboxElement = vm.$el.querySelector('#remove-source-branch-input');
-
- expect(checkboxElement).toBeNull();
- });
- });
-
- describe('when user can merge and can delete branch', () => {
- beforeEach(() => {
- vm = createComponent({
- mr: { canRemoveSourceBranch: true },
- });
- });
-
- it('isRemoveSourceBranchButtonDisabled should be false', () => {
- expect(vm.isRemoveSourceBranchButtonDisabled).toBe(false);
- });
-
- it('removed source branch should be enabled in rendered output', () => {
- const checkboxElement = vm.$el.querySelector('#remove-source-branch-input');
-
- expect(checkboxElement).not.toBeNull();
- });
- });
- });
-
- describe('render children components', () => {
- let wrapper;
- const localVue = createLocalVue();
-
- const createLocalComponent = (customConfig = {}) => {
- wrapper = shallowMount(localVue.extend(ReadyToMerge), {
- localVue,
- propsData: {
- mr: createTestMr(customConfig),
- service: createTestService(),
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const findCheckboxElement = () => wrapper.find(SquashBeforeMerge);
- const findCommitsHeaderElement = () => wrapper.find(CommitsHeader);
- const findCommitEditElements = () => wrapper.findAll(CommitEdit);
- const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown);
- const findFirstCommitEditLabel = () =>
- findCommitEditElements()
- .at(0)
- .props('label');
-
- describe('squash checkbox', () => {
- it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => {
- createLocalComponent({
- mr: { commitsCount: 2, enableSquashBeforeMerge: true },
- });
-
- expect(findCheckboxElement().exists()).toBeTruthy();
- });
-
- it('should not be rendered when squash before merge is disabled', () => {
- createLocalComponent({ mr: { commitsCount: 2, enableSquashBeforeMerge: false } });
-
- expect(findCheckboxElement().exists()).toBeFalsy();
- });
-
- it('should not be rendered when there is only 1 commit', () => {
- createLocalComponent({ mr: { commitsCount: 1, enableSquashBeforeMerge: true } });
-
- expect(findCheckboxElement().exists()).toBeFalsy();
- });
- });
-
- describe('commits count collapsible header', () => {
- it('should be rendered when fast-forward is disabled', () => {
- createLocalComponent();
-
- expect(findCommitsHeaderElement().exists()).toBeTruthy();
- });
-
- describe('when fast-forward is enabled', () => {
- it('should be rendered if squash and squash before are enabled and there is more than 1 commit', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- enableSquashBeforeMerge: true,
- squash: true,
- commitsCount: 2,
- },
- });
-
- expect(findCommitsHeaderElement().exists()).toBeTruthy();
- });
-
- it('should not be rendered if squash before merge is disabled', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- enableSquashBeforeMerge: false,
- squash: true,
- commitsCount: 2,
- },
- });
-
- expect(findCommitsHeaderElement().exists()).toBeFalsy();
- });
-
- it('should not be rendered if squash is disabled', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: false,
- enableSquashBeforeMerge: true,
- commitsCount: 2,
- },
- });
-
- expect(findCommitsHeaderElement().exists()).toBeFalsy();
- });
-
- it('should not be rendered if commits count is 1', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: true,
- enableSquashBeforeMerge: true,
- commitsCount: 1,
- },
- });
-
- expect(findCommitsHeaderElement().exists()).toBeFalsy();
- });
- });
- });
-
- describe('commits edit components', () => {
- describe('when fast-forward merge is enabled', () => {
- it('should not be rendered if squash is disabled', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: false,
- enableSquashBeforeMerge: true,
- commitsCount: 2,
- },
- });
-
- expect(findCommitEditElements().length).toBe(0);
- });
-
- it('should not be rendered if squash before merge is disabled', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: true,
- enableSquashBeforeMerge: false,
- commitsCount: 2,
- },
- });
-
- expect(findCommitEditElements().length).toBe(0);
- });
-
- it('should not be rendered if there is only one commit', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: true,
- enableSquashBeforeMerge: true,
- commitsCount: 1,
- },
- });
-
- expect(findCommitEditElements().length).toBe(0);
- });
-
- it('should have one edit component if squash is enabled and there is more than 1 commit', () => {
- createLocalComponent({
- mr: {
- ffOnlyEnabled: true,
- squash: true,
- enableSquashBeforeMerge: true,
- commitsCount: 2,
- },
- });
-
- expect(findCommitEditElements().length).toBe(1);
- expect(findFirstCommitEditLabel()).toBe('Squash commit message');
- });
- });
-
- it('should have one edit component when squash is disabled', () => {
- createLocalComponent();
-
- expect(findCommitEditElements().length).toBe(1);
- });
-
- it('should have two edit components when squash is enabled and there is more than 1 commit', () => {
- createLocalComponent({
- mr: {
- commitsCount: 2,
- squash: true,
- enableSquashBeforeMerge: true,
- },
- });
-
- expect(findCommitEditElements().length).toBe(2);
- });
-
- it('should have one edit components when squash is enabled and there is 1 commit only', () => {
- createLocalComponent({
- mr: {
- commitsCount: 1,
- squash: true,
- enableSquashBeforeMerge: true,
- },
- });
-
- expect(findCommitEditElements().length).toBe(1);
- });
-
- it('should have correct edit merge commit label', () => {
- createLocalComponent();
-
- expect(findFirstCommitEditLabel()).toBe('Merge commit message');
- });
-
- it('should have correct edit squash commit label', () => {
- createLocalComponent({
- mr: {
- commitsCount: 2,
- squash: true,
- enableSquashBeforeMerge: true,
- },
- });
-
- expect(findFirstCommitEditLabel()).toBe('Squash commit message');
- });
- });
-
- describe('commits dropdown', () => {
- it('should not be rendered if squash is disabled', () => {
- createLocalComponent();
-
- expect(findCommitDropdownElement().exists()).toBeFalsy();
- });
-
- it('should be rendered if squash is enabled and there is more than 1 commit', () => {
- createLocalComponent({
- mr: { enableSquashBeforeMerge: true, squash: true, commitsCount: 2 },
- });
-
- expect(findCommitDropdownElement().exists()).toBeTruthy();
- });
- });
- });
-
- describe('Merge controls', () => {
- describe('when allowed to merge', () => {
- beforeEach(() => {
- vm = createComponent({
- mr: { isMergeAllowed: true, canRemoveSourceBranch: true },
- });
- });
-
- it('shows remove source branch checkbox', () => {
- expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).not.toBeNull();
- });
-
- it('shows modify commit message button', () => {
- expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined();
- });
-
- it('does not show message about needing to resolve items', () => {
- expect(vm.$el.querySelector('.js-resolve-mr-widget-items-message')).toBeNull();
- });
- });
-
- describe('when not allowed to merge', () => {
- beforeEach(() => {
- vm = createComponent({
- mr: { isMergeAllowed: false },
- });
- });
-
- it('does not show remove source branch checkbox', () => {
- expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).toBeNull();
- });
-
- it('shows message to resolve all items before being allowed to merge', () => {
- expect(vm.$el.querySelector('.js-resolve-mr-widget-items-message')).toBeDefined();
- });
- });
- });
-
- describe('Merge request project settings', () => {
- describe('when the merge commit merge method is enabled', () => {
- beforeEach(() => {
- vm = createComponent({
- mr: { ffOnlyEnabled: false },
- });
- });
-
- it('should not show fast forward message', () => {
- expect(vm.$el.querySelector('.mr-fast-forward-message')).toBeNull();
- });
-
- it('should show "Modify commit message" button', () => {
- expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined();
- });
- });
-
- describe('when the fast-forward merge method is enabled', () => {
- beforeEach(() => {
- vm = createComponent({
- mr: { ffOnlyEnabled: true },
- });
- });
-
- it('should show fast forward message', () => {
- expect(vm.$el.querySelector('.mr-fast-forward-message')).toBeDefined();
- });
-
- it('should not show "Modify commit message" button', () => {
- expect(vm.$el.querySelector('.js-modify-commit-message-button')).toBeNull();
- });
- });
- });
-
- describe('with a mismatched SHA', () => {
- const findMismatchShaBlock = () => vm.$el.querySelector('.js-sha-mismatch');
-
- beforeEach(() => {
- vm = createComponent({
- mr: {
- isSHAMismatch: true,
- mergeRequestDiffsPath: '/merge_requests/1/diffs',
- },
- });
- });
-
- it('displays a warning message', () => {
- expect(findMismatchShaBlock()).toExist();
- });
-
- it('warns the user to refresh to review', () => {
- expect(findMismatchShaBlock().textContent.trim()).toBe(
- 'New changes were added. Reload the page to review them',
- );
- });
-
- it('displays link to the diffs tab', () => {
- expect(findMismatchShaBlock().querySelector('a').href).toContain(vm.mr.mergeRequestDiffsPath);
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js
deleted file mode 100644
index 11eb0fef9b2..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { removeBreakLine } from 'spec/helpers/text_helper';
-import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue';
-
-describe('ShaMismatch', () => {
- let vm;
-
- beforeEach(() => {
- const Component = Vue.extend(ShaMismatch);
- vm = mountComponent(Component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('should render information message', () => {
- expect(vm.$el.querySelector('button').disabled).toEqual(true);
-
- expect(removeBreakLine(vm.$el.textContent).trim()).toContain(
- 'The source branch HEAD has recently changed. Please reload the page and review the changes before merging',
- );
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
deleted file mode 100644
index b70d580ed04..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
-
-const localVue = createLocalVue();
-
-describe('Squash before merge component', () => {
- let wrapper;
-
- const createComponent = props => {
- wrapper = shallowMount(localVue.extend(SquashBeforeMerge), {
- localVue,
- propsData: {
- ...props,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('checkbox', () => {
- const findCheckbox = () => wrapper.find('.js-squash-checkbox');
-
- it('is unchecked if passed value prop is false', () => {
- createComponent({
- value: false,
- });
-
- expect(findCheckbox().element.checked).toBeFalsy();
- });
-
- it('is checked if passed value prop is true', () => {
- createComponent({
- value: true,
- });
-
- expect(findCheckbox().element.checked).toBeTruthy();
- });
-
- it('changes value on click', done => {
- createComponent({
- value: false,
- });
-
- findCheckbox().element.checked = true;
-
- findCheckbox().trigger('change');
-
- wrapper.vm.$nextTick(() => {
- expect(findCheckbox().element.checked).toBeTruthy();
- done();
- });
- });
-
- it('is disabled if isDisabled prop is true', () => {
- createComponent({
- value: false,
- isDisabled: true,
- });
-
- expect(findCheckbox().attributes('disabled')).toBeTruthy();
- });
- });
-
- describe('about link', () => {
- it('is not rendered if no help path is passed', () => {
- createComponent({
- value: false,
- });
-
- const aboutLink = wrapper.find('a');
-
- expect(aboutLink.exists()).toBeFalsy();
- });
-
- it('is rendered if help path is passed', () => {
- createComponent({
- value: false,
- helpPath: 'test-path',
- });
-
- const aboutLink = wrapper.find('a');
-
- expect(aboutLink.exists()).toBeTruthy();
- });
-
- it('should have a correct help path if passed', () => {
- createComponent({
- value: false,
- helpPath: 'test-path',
- });
-
- const aboutLink = wrapper.find('a');
-
- expect(aboutLink.attributes('href')).toEqual('test-path');
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js
deleted file mode 100644
index e8367caa438..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import UnresolvedDiscussions from '~/vue_merge_request_widget/components/states/unresolved_discussions.vue';
-
-describe('UnresolvedDiscussions', () => {
- const Component = Vue.extend(UnresolvedDiscussions);
- let vm;
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('with threads path', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- mr: {
- createIssueToResolveDiscussionsPath: gl.TEST_HOST,
- },
- });
- });
-
- it('should have correct elements', () => {
- expect(vm.$el.innerText).toContain(
- 'There are unresolved threads. Please resolve these threads',
- );
-
- expect(vm.$el.innerText).toContain('Create an issue to resolve them later');
- expect(vm.$el.querySelector('.js-create-issue').getAttribute('href')).toEqual(gl.TEST_HOST);
- });
- });
-
- describe('without threads path', () => {
- beforeEach(() => {
- vm = mountComponent(Component, { mr: {} });
- });
-
- it('should not show create issue link if user cannot create issue', () => {
- expect(vm.$el.innerText).toContain(
- 'There are unresolved threads. Please resolve these threads',
- );
-
- expect(vm.$el.querySelector('.js-create-issue')).toEqual(null);
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js
deleted file mode 100644
index 9153231b974..00000000000
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import Vue from 'vue';
-import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-
-const createComponent = () => {
- const Component = Vue.extend(WorkInProgress);
- const mr = {
- title: 'The best MR ever',
- removeWIPPath: '/path/to/remove/wip',
- };
- const service = {
- removeWIP() {},
- };
- return new Component({
- el: document.createElement('div'),
- propsData: { mr, service },
- });
-};
-
-describe('Wip', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr, service } = WorkInProgress.props;
-
- expect(mr.type instanceof Object).toBeTruthy();
- expect(mr.required).toBeTruthy();
-
- expect(service.type instanceof Object).toBeTruthy();
- expect(service.required).toBeTruthy();
- });
- });
-
- describe('data', () => {
- it('should have default data', () => {
- const vm = createComponent();
-
- expect(vm.isMakingRequest).toBeFalsy();
- });
- });
-
- describe('methods', () => {
- const mrObj = {
- is_new_mr_data: true,
- };
-
- describe('handleRemoveWIP', () => {
- it('should make a request to service and handle response', done => {
- const vm = createComponent();
-
- const flashSpy = spyOnDependency(WorkInProgress, 'createFlash').and.returnValue(true);
- spyOn(eventHub, '$emit');
- spyOn(vm.service, 'removeWIP').and.returnValue(
- new Promise(resolve => {
- resolve({
- data: mrObj,
- });
- }),
- );
-
- vm.handleRemoveWIP();
- setTimeout(() => {
- expect(vm.isMakingRequest).toBeTruthy();
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- expect(flashSpy).toHaveBeenCalledWith('The merge request can now be merged.', 'notice');
- done();
- }, 333);
- });
- });
- });
-
- 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('This is a Work in Progress');
- expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy();
- expect(el.querySelector('button').innerText).toContain('Merge');
- expect(el.querySelector('.js-remove-wip').innerText.replace(/\s\s+/g, ' ')).toContain(
- 'Resolve WIP status',
- );
- });
-
- it('should not show removeWIP button is user cannot update MR', done => {
- vm.mr.removeWIPPath = '';
-
- Vue.nextTick(() => {
- expect(el.querySelector('.js-remove-wip')).toEqual(null);
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
deleted file mode 100644
index 7783fcb6f93..00000000000
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export { default } from '../../frontend/vue_mr_widget/mock_data';
-export * from '../../frontend/vue_mr_widget/mock_data';
diff --git a/spec/javascripts/vue_shared/components/deprecated_modal_2_spec.js b/spec/javascripts/vue_shared/components/deprecated_modal_2_spec.js
deleted file mode 100644
index e031583b43a..00000000000
--- a/spec/javascripts/vue_shared/components/deprecated_modal_2_spec.js
+++ /dev/null
@@ -1,261 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
-
-const modalComponent = Vue.extend(DeprecatedModal2);
-
-describe('DeprecatedModal2', () => {
- let vm;
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('props', () => {
- describe('with id', () => {
- const props = {
- id: 'my-modal',
- };
-
- beforeEach(() => {
- vm = mountComponent(modalComponent, props);
- });
-
- it('assigns the id to the modal', () => {
- expect(vm.$el.id).toBe(props.id);
- });
- });
-
- describe('without id', () => {
- beforeEach(() => {
- vm = mountComponent(modalComponent, {});
- });
-
- it('does not add an id attribute to the modal', () => {
- expect(vm.$el.hasAttribute('id')).toBe(false);
- });
- });
-
- describe('with headerTitleText', () => {
- const props = {
- headerTitleText: 'my title text',
- };
-
- beforeEach(() => {
- vm = mountComponent(modalComponent, props);
- });
-
- it('sets the modal title', () => {
- const modalTitle = vm.$el.querySelector('.modal-title');
-
- expect(modalTitle.innerHTML.trim()).toBe(props.headerTitleText);
- });
- });
-
- describe('with footerPrimaryButtonVariant', () => {
- const props = {
- footerPrimaryButtonVariant: 'danger',
- };
-
- beforeEach(() => {
- vm = mountComponent(modalComponent, props);
- });
-
- it('sets the primary button class', () => {
- const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type');
-
- expect(primaryButton).toHaveClass(`btn-${props.footerPrimaryButtonVariant}`);
- });
- });
-
- describe('with footerPrimaryButtonText', () => {
- const props = {
- footerPrimaryButtonText: 'my button text',
- };
-
- beforeEach(() => {
- vm = mountComponent(modalComponent, props);
- });
-
- it('sets the primary button text', () => {
- const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type');
-
- expect(primaryButton.innerHTML.trim()).toBe(props.footerPrimaryButtonText);
- });
- });
- });
-
- it('works with data-toggle="modal"', done => {
- setFixtures(`
- <button id="modal-button" data-toggle="modal" data-target="#my-modal"></button>
- <div id="modal-container"></div>
- `);
-
- const modalContainer = document.getElementById('modal-container');
- const modalButton = document.getElementById('modal-button');
- vm = mountComponent(
- modalComponent,
- {
- id: 'my-modal',
- },
- modalContainer,
- );
- $(vm.$el).on('shown.bs.modal', () => done());
-
- modalButton.click();
- });
-
- describe('methods', () => {
- const dummyEvent = 'not really an event';
-
- beforeEach(() => {
- vm = mountComponent(modalComponent, {});
- spyOn(vm, '$emit');
- });
-
- describe('emitCancel', () => {
- it('emits a cancel event', () => {
- vm.emitCancel(dummyEvent);
-
- expect(vm.$emit).toHaveBeenCalledWith('cancel', dummyEvent);
- });
- });
-
- describe('emitSubmit', () => {
- it('emits a submit event', () => {
- vm.emitSubmit(dummyEvent);
-
- expect(vm.$emit).toHaveBeenCalledWith('submit', dummyEvent);
- });
- });
-
- describe('opened', () => {
- it('emits a open event', () => {
- vm.opened();
-
- expect(vm.$emit).toHaveBeenCalledWith('open');
- });
- });
-
- describe('closed', () => {
- it('emits a closed event', () => {
- vm.closed();
-
- expect(vm.$emit).toHaveBeenCalledWith('closed');
- });
- });
- });
-
- describe('slots', () => {
- const slotContent = 'this should go into the slot';
- const modalWithSlot = slotName => {
- let template;
- if (slotName) {
- template = `
- <deprecated-modal-2>
- <template slot="${slotName}">${slotContent}</template>
- </deprecated-modal-2>
- `;
- } else {
- template = `<deprecated-modal-2>${slotContent}</deprecated-modal-2>`;
- }
-
- return Vue.extend({
- components: {
- DeprecatedModal2,
- },
- template,
- });
- };
-
- describe('default slot', () => {
- beforeEach(() => {
- vm = mountComponent(modalWithSlot());
- });
-
- it('sets the modal body', () => {
- const modalBody = vm.$el.querySelector('.modal-body');
-
- expect(modalBody.innerHTML).toBe(slotContent);
- });
- });
-
- describe('header slot', () => {
- beforeEach(() => {
- vm = mountComponent(modalWithSlot('header'));
- });
-
- it('sets the modal header', () => {
- const modalHeader = vm.$el.querySelector('.modal-header');
-
- expect(modalHeader.innerHTML).toBe(slotContent);
- });
- });
-
- describe('title slot', () => {
- beforeEach(() => {
- vm = mountComponent(modalWithSlot('title'));
- });
-
- it('sets the modal title', () => {
- const modalTitle = vm.$el.querySelector('.modal-title');
-
- expect(modalTitle.innerHTML).toBe(slotContent);
- });
- });
-
- describe('footer slot', () => {
- beforeEach(() => {
- vm = mountComponent(modalWithSlot('footer'));
- });
-
- it('sets the modal footer', () => {
- const modalFooter = vm.$el.querySelector('.modal-footer');
-
- expect(modalFooter.innerHTML).toBe(slotContent);
- });
- });
- });
-
- describe('handling sizes', () => {
- it('should render modal-sm', () => {
- vm = mountComponent(modalComponent, {
- modalSize: 'sm',
- });
-
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(true);
- });
-
- it('should render modal-lg', () => {
- vm = mountComponent(modalComponent, {
- modalSize: 'lg',
- });
-
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(true);
- });
-
- it('should render modal-xl', () => {
- vm = mountComponent(modalComponent, {
- modalSize: 'xl',
- });
-
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-xl')).toEqual(true);
- });
-
- it('should not add modal size classes when md size is passed', () => {
- vm = mountComponent(modalComponent, {
- modalSize: 'md',
- });
-
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-md')).toEqual(false);
- });
-
- it('should not add modal size classes by default', () => {
- vm = mountComponent(modalComponent, {});
-
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(false);
- expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(false);
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/components/deprecated_modal_spec.js b/spec/javascripts/vue_shared/components/deprecated_modal_spec.js
deleted file mode 100644
index d6c10e32794..00000000000
--- a/spec/javascripts/vue_shared/components/deprecated_modal_spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
-
-const modalComponent = Vue.extend(DeprecatedModal);
-
-describe('DeprecatedModal', () => {
- let vm;
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('props', () => {
- describe('without primaryButtonLabel', () => {
- beforeEach(() => {
- vm = mountComponent(modalComponent, {
- primaryButtonLabel: null,
- });
- });
-
- it('does not render a primary button', () => {
- expect(vm.$el.querySelector('.js-primary-button')).toBeNull();
- });
- });
-
- describe('with id', () => {
- describe('does not render a primary button', () => {
- beforeEach(() => {
- vm = mountComponent(modalComponent, {
- id: 'my-modal',
- });
- });
-
- it('assigns the id to the modal', () => {
- expect(vm.$el.querySelector('#my-modal.modal')).not.toBeNull();
- });
-
- it('does not show the modal immediately', () => {
- expect(vm.$el.querySelector('#my-modal.modal')).not.toHaveClass('show');
- });
-
- it('does not show a backdrop', () => {
- expect(vm.$el.querySelector('modal-backdrop')).toBeNull();
- });
- });
- });
-
- it('works with data-toggle="modal"', done => {
- setFixtures(`
- <button id="modal-button" data-toggle="modal" data-target="#my-modal"></button>
- <div id="modal-container"></div>
- `);
-
- const modalContainer = document.getElementById('modal-container');
- const modalButton = document.getElementById('modal-button');
- vm = mountComponent(
- modalComponent,
- {
- id: 'my-modal',
- },
- modalContainer,
- );
- const modalElement = vm.$el.querySelector('#my-modal');
- $(modalElement).on('shown.bs.modal', () => done());
-
- modalButton.click();
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/components/file_finder/index_spec.js b/spec/javascripts/vue_shared/components/file_finder/index_spec.js
deleted file mode 100644
index 7ded228d3ea..00000000000
--- a/spec/javascripts/vue_shared/components/file_finder/index_spec.js
+++ /dev/null
@@ -1,368 +0,0 @@
-import Vue from 'vue';
-import Mousetrap from 'mousetrap';
-import { file } from 'spec/ide/helpers';
-import timeoutPromise from 'spec/helpers/set_timeout_promise_helper';
-import FindFileComponent from '~/vue_shared/components/file_finder/index.vue';
-import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
-
-describe('File finder item spec', () => {
- const Component = Vue.extend(FindFileComponent);
- let vm;
-
- function createComponent(props) {
- vm = new Component({
- propsData: {
- files: [],
- visible: true,
- loading: false,
- ...props,
- },
- });
-
- vm.$mount('#app');
- }
-
- beforeEach(() => {
- setFixtures('<div id="app"></div>');
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('with entries', () => {
- beforeEach(done => {
- createComponent({
- files: [
- {
- ...file('index.js'),
- path: 'index.js',
- type: 'blob',
- url: '/index.jsurl',
- },
- {
- ...file('component.js'),
- path: 'component.js',
- type: 'blob',
- },
- ],
- });
-
- setTimeout(done);
- });
-
- it('renders list of blobs', () => {
- expect(vm.$el.textContent).toContain('index.js');
- expect(vm.$el.textContent).toContain('component.js');
- expect(vm.$el.textContent).not.toContain('folder');
- });
-
- it('filters entries', done => {
- vm.searchText = 'index';
-
- setTimeout(() => {
- expect(vm.$el.textContent).toContain('index.js');
- expect(vm.$el.textContent).not.toContain('component.js');
-
- done();
- });
- });
-
- it('shows clear button when searchText is not empty', done => {
- vm.searchText = 'index';
-
- setTimeout(() => {
- expect(vm.$el.querySelector('.dropdown-input').classList).toContain('has-value');
- expect(vm.$el.querySelector('.dropdown-input-search').classList).toContain('hidden');
-
- done();
- });
- });
-
- it('clear button resets searchText', done => {
- vm.searchText = 'index';
-
- timeoutPromise()
- .then(() => {
- vm.$el.querySelector('.dropdown-input-clear').click();
- })
- .then(timeoutPromise)
- .then(() => {
- expect(vm.searchText).toBe('');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('clear button focues search input', done => {
- spyOn(vm.$refs.searchInput, 'focus');
- vm.searchText = 'index';
-
- timeoutPromise()
- .then(() => {
- vm.$el.querySelector('.dropdown-input-clear').click();
- })
- .then(timeoutPromise)
- .then(() => {
- expect(vm.$refs.searchInput.focus).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- describe('listShowCount', () => {
- it('returns 1 when no filtered entries exist', done => {
- vm.searchText = 'testing 123';
-
- setTimeout(() => {
- expect(vm.listShowCount).toBe(1);
-
- done();
- });
- });
-
- it('returns entries length when not filtered', () => {
- expect(vm.listShowCount).toBe(2);
- });
- });
-
- describe('listHeight', () => {
- it('returns 55 when entries exist', () => {
- expect(vm.listHeight).toBe(55);
- });
-
- it('returns 33 when entries dont exist', done => {
- vm.searchText = 'testing 123';
-
- setTimeout(() => {
- expect(vm.listHeight).toBe(33);
-
- done();
- });
- });
- });
-
- describe('filteredBlobsLength', () => {
- it('returns length of filtered blobs', done => {
- vm.searchText = 'index';
-
- setTimeout(() => {
- expect(vm.filteredBlobsLength).toBe(1);
-
- done();
- });
- });
- });
-
- describe('watches', () => {
- describe('searchText', () => {
- it('resets focusedIndex when updated', done => {
- vm.focusedIndex = 1;
- vm.searchText = 'test';
-
- setTimeout(() => {
- expect(vm.focusedIndex).toBe(0);
-
- done();
- });
- });
- });
-
- describe('visible', () => {
- it('returns searchText when false', done => {
- vm.searchText = 'test';
- vm.visible = true;
-
- timeoutPromise()
- .then(() => {
- vm.visible = false;
- })
- .then(timeoutPromise)
- .then(() => {
- expect(vm.searchText).toBe('');
- })
- .then(done)
- .catch(done.fail);
- });
- });
- });
-
- describe('openFile', () => {
- beforeEach(() => {
- spyOn(vm, '$emit');
- });
-
- it('closes file finder', () => {
- vm.openFile(vm.files[0]);
-
- expect(vm.$emit).toHaveBeenCalledWith('toggle', false);
- });
-
- it('pushes to router', () => {
- vm.openFile(vm.files[0]);
-
- expect(vm.$emit).toHaveBeenCalledWith('click', vm.files[0]);
- });
- });
-
- describe('onKeyup', () => {
- it('opens file on enter key', done => {
- const event = new CustomEvent('keyup');
- event.keyCode = ENTER_KEY_CODE;
-
- spyOn(vm, 'openFile');
-
- vm.$refs.searchInput.dispatchEvent(event);
-
- setTimeout(() => {
- expect(vm.openFile).toHaveBeenCalledWith(vm.files[0]);
-
- done();
- });
- });
-
- it('closes file finder on esc key', done => {
- const event = new CustomEvent('keyup');
- event.keyCode = ESC_KEY_CODE;
-
- spyOn(vm, '$emit');
-
- vm.$refs.searchInput.dispatchEvent(event);
-
- setTimeout(() => {
- expect(vm.$emit).toHaveBeenCalledWith('toggle', false);
-
- done();
- });
- });
- });
-
- describe('onKeyDown', () => {
- let el;
-
- beforeEach(() => {
- el = vm.$refs.searchInput;
- });
-
- describe('up key', () => {
- const event = new CustomEvent('keydown');
- event.keyCode = UP_KEY_CODE;
-
- it('resets to last index when at top', () => {
- el.dispatchEvent(event);
-
- expect(vm.focusedIndex).toBe(1);
- });
-
- it('minus 1 from focusedIndex', () => {
- vm.focusedIndex = 1;
-
- el.dispatchEvent(event);
-
- expect(vm.focusedIndex).toBe(0);
- });
- });
-
- describe('down key', () => {
- const event = new CustomEvent('keydown');
- event.keyCode = DOWN_KEY_CODE;
-
- it('resets to first index when at bottom', () => {
- vm.focusedIndex = 1;
- el.dispatchEvent(event);
-
- expect(vm.focusedIndex).toBe(0);
- });
-
- it('adds 1 to focusedIndex', () => {
- el.dispatchEvent(event);
-
- expect(vm.focusedIndex).toBe(1);
- });
- });
- });
- });
-
- describe('without entries', () => {
- it('renders loading text when loading', () => {
- createComponent({
- loading: true,
- });
-
- expect(vm.$el.textContent).toContain('Loading...');
- });
-
- it('renders no files text', () => {
- createComponent();
-
- expect(vm.$el.textContent).toContain('No files found.');
- });
- });
-
- describe('keyboard shortcuts', () => {
- beforeEach(done => {
- createComponent();
-
- spyOn(vm, 'toggle');
-
- vm.$nextTick(done);
- });
-
- it('calls toggle on `t` key press', done => {
- Mousetrap.trigger('t');
-
- vm.$nextTick()
- .then(() => {
- expect(vm.toggle).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('calls toggle on `command+p` key press', done => {
- Mousetrap.trigger('command+p');
-
- vm.$nextTick()
- .then(() => {
- expect(vm.toggle).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('calls toggle on `ctrl+p` key press', done => {
- Mousetrap.trigger('ctrl+p');
-
- vm.$nextTick()
- .then(() => {
- expect(vm.toggle).toHaveBeenCalled();
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('always allows `command+p` to trigger toggle', () => {
- expect(
- vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 'command+p'),
- ).toBe(false);
- });
-
- it('always allows `ctrl+p` to trigger toggle', () => {
- expect(
- vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 'ctrl+p'),
- ).toBe(false);
- });
-
- it('onlys handles `t` when focused in input-field', () => {
- expect(
- vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 't'),
- ).toBe(true);
- });
-
- it('stops callback in monaco editor', () => {
- setFixtures('<div class="inputarea"></div>');
-
- expect(vm.mousetrapStopCallback(null, document.querySelector('.inputarea'), 't')).toBe(true);
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/components/icon_spec.js b/spec/javascripts/vue_shared/components/icon_spec.js
deleted file mode 100644
index 5a3e483fb03..00000000000
--- a/spec/javascripts/vue_shared/components/icon_spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import Vue from 'vue';
-import { mount } from '@vue/test-utils';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import Icon from '~/vue_shared/components/icon.vue';
-
-describe('Sprite Icon Component', function() {
- describe('Initialization', function() {
- let icon;
-
- beforeEach(function() {
- const IconComponent = Vue.extend(Icon);
-
- icon = mountComponent(IconComponent, {
- name: 'commit',
- size: 32,
- });
- });
-
- afterEach(() => {
- icon.$destroy();
- });
-
- it('should return a defined Vue component', function() {
- expect(icon).toBeDefined();
- });
-
- it('should have <svg> as a child element', function() {
- expect(icon.$el.tagName).toBe('svg');
- });
-
- it('should have <use> as a child element with the correct href', function() {
- expect(icon.$el.firstChild.tagName).toBe('use');
- expect(icon.$el.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_icons}#commit`);
- });
-
- it('should properly compute iconSizeClass', function() {
- expect(icon.iconSizeClass).toBe('s32');
- });
-
- it('forbids invalid size prop', () => {
- expect(icon.$options.props.size.validator(NaN)).toBeFalsy();
- expect(icon.$options.props.size.validator(0)).toBeFalsy();
- expect(icon.$options.props.size.validator(9001)).toBeFalsy();
- });
-
- it('should properly render img css', function() {
- const { classList } = icon.$el;
- const containsSizeClass = classList.contains('s32');
-
- expect(containsSizeClass).toBe(true);
- });
-
- it('`name` validator should return false for non existing icons', () => {
- expect(Icon.props.name.validator('non_existing_icon_sprite')).toBe(false);
- });
-
- it('`name` validator should return false for existing icons', () => {
- expect(Icon.props.name.validator('commit')).toBe(true);
- });
- });
-
- it('should call registered listeners when they are triggered', () => {
- const clickHandler = jasmine.createSpy('clickHandler');
- const wrapper = mount(Icon, {
- propsData: { name: 'commit' },
- listeners: { click: clickHandler },
- });
-
- wrapper.find('svg').trigger('click');
-
- expect(clickHandler).toHaveBeenCalled();
- });
-});
diff --git a/spec/javascripts/vue_shared/components/issue/related_issuable_mock_data.js b/spec/javascripts/vue_shared/components/issue/related_issuable_mock_data.js
deleted file mode 100644
index 3c42f0c2aa9..00000000000
--- a/spec/javascripts/vue_shared/components/issue/related_issuable_mock_data.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from '../../../../frontend/vue_shared/components/issue/related_issuable_mock_data';
diff --git a/spec/javascripts/vue_shared/components/panel_resizer_spec.js b/spec/javascripts/vue_shared/components/panel_resizer_spec.js
deleted file mode 100644
index d65ee8eeb2d..00000000000
--- a/spec/javascripts/vue_shared/components/panel_resizer_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import panelResizer from '~/vue_shared/components/panel_resizer.vue';
-
-describe('Panel Resizer component', () => {
- let vm;
- let PanelResizer;
-
- const triggerEvent = (eventName, el = vm.$el, clientX = 0) => {
- const event = document.createEvent('MouseEvents');
- event.initMouseEvent(
- eventName,
- true,
- true,
- window,
- 1,
- clientX,
- 0,
- clientX,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- );
-
- el.dispatchEvent(event);
- };
-
- beforeEach(() => {
- PanelResizer = Vue.extend(panelResizer);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('should render a div element with the correct classes and styles', () => {
- vm = mountComponent(PanelResizer, {
- startSize: 100,
- side: 'left',
- });
-
- expect(vm.$el.tagName).toEqual('DIV');
- expect(vm.$el.getAttribute('class')).toBe(
- 'position-absolute position-top-0 position-bottom-0 drag-handle position-left-0',
- );
-
- expect(vm.$el.getAttribute('style')).toBe('cursor: ew-resize;');
- });
-
- it('should render a div element with the correct classes for a right side panel', () => {
- vm = mountComponent(PanelResizer, {
- startSize: 100,
- side: 'right',
- });
-
- expect(vm.$el.tagName).toEqual('DIV');
- expect(vm.$el.getAttribute('class')).toBe(
- 'position-absolute position-top-0 position-bottom-0 drag-handle position-right-0',
- );
- });
-
- it('drag the resizer', () => {
- vm = mountComponent(PanelResizer, {
- startSize: 100,
- side: 'left',
- });
-
- spyOn(vm, '$emit');
- triggerEvent('mousedown', vm.$el);
- triggerEvent('mousemove', document);
- triggerEvent('mouseup', document);
-
- expect(vm.$emit.calls.allArgs()).toEqual([
- ['resize-start', 100],
- ['update:size', 100],
- ['resize-end', 100],
- ]);
-
- expect(vm.size).toBe(100);
- });
-});
diff --git a/spec/javascripts/vue_shared/components/smart_virtual_list_spec.js b/spec/javascripts/vue_shared/components/smart_virtual_list_spec.js
deleted file mode 100644
index 47ebdc505c9..00000000000
--- a/spec/javascripts/vue_shared/components/smart_virtual_list_spec.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import SmartVirtualScrollList from '~/vue_shared/components/smart_virtual_list.vue';
-
-describe('Toggle Button', () => {
- let vm;
-
- const createComponent = ({ length, remain }) => {
- const smartListProperties = {
- rtag: 'section',
- wtag: 'ul',
- wclass: 'test-class',
- // Size in pixels does not matter for our tests here
- size: 35,
- length,
- remain,
- };
-
- const Component = Vue.extend({
- components: {
- SmartVirtualScrollList,
- },
- smartListProperties,
- items: Array(length).fill(1),
- template: `
- <smart-virtual-scroll-list v-bind="$options.smartListProperties">
- <li v-for="(val, key) in $options.items" :key="key">{{ key + 1 }}</li>
- </smart-virtual-scroll-list>`,
- });
-
- return mountComponent(Component);
- };
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('if the list is shorter than the maximum shown elements', () => {
- const listLength = 10;
-
- beforeEach(() => {
- vm = createComponent({ length: listLength, remain: 20 });
- });
-
- it('renders without the vue-virtual-scroll-list component', () => {
- expect(vm.$el.classList).not.toContain('js-virtual-list');
- expect(vm.$el.classList).toContain('js-plain-element');
- });
-
- it('renders list with provided tags and classes for the wrapper elements', () => {
- expect(vm.$el.tagName).toEqual('SECTION');
- expect(vm.$el.firstChild.tagName).toEqual('UL');
- expect(vm.$el.firstChild.classList).toContain('test-class');
- });
-
- it('renders all children list elements', () => {
- expect(vm.$el.querySelectorAll('li').length).toEqual(listLength);
- });
- });
-
- describe('if the list is longer than the maximum shown elements', () => {
- const maxItemsShown = 20;
-
- beforeEach(() => {
- vm = createComponent({ length: 1000, remain: maxItemsShown });
- });
-
- it('uses the vue-virtual-scroll-list component', () => {
- expect(vm.$el.classList).toContain('js-virtual-list');
- expect(vm.$el.classList).not.toContain('js-plain-element');
- });
-
- it('renders list with provided tags and classes for the wrapper elements', () => {
- expect(vm.$el.tagName).toEqual('SECTION');
- expect(vm.$el.firstChild.tagName).toEqual('UL');
- expect(vm.$el.firstChild.classList).toContain('test-class');
- });
-
- it('renders at max twice the maximum shown elements', () => {
- expect(vm.$el.querySelectorAll('li').length).toBeLessThanOrEqual(2 * maxItemsShown);
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js b/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js
deleted file mode 100644
index f1ca5f61496..00000000000
--- a/spec/javascripts/vue_shared/directives/autofocusonshow_spec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
-
-/**
- * We're testing this directive's hooks as pure functions
- * since behaviour of this directive is highly-dependent
- * on underlying DOM methods.
- */
-describe('AutofocusOnShow directive', () => {
- describe('with input invisible on component render', () => {
- let el;
-
- beforeAll(() => {
- setFixtures('<div id="container" style="display: none;"><input id="inputel"/></div>');
- el = document.querySelector('#inputel');
- });
-
- it('should bind IntersectionObserver on input element', () => {
- spyOn(el, 'focus');
-
- autofocusonshow.inserted(el);
-
- expect(el.visibilityObserver).toBeDefined();
- expect(el.focus).not.toHaveBeenCalled();
- });
-
- it('should stop IntersectionObserver on input element on unbind hook', () => {
- el.visibilityObserver = {
- disconnect: () => {},
- };
- spyOn(el.visibilityObserver, 'disconnect');
-
- autofocusonshow.unbind(el);
-
- expect(el.visibilityObserver).toBeDefined();
- expect(el.visibilityObserver.disconnect).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/directives/tooltip_spec.js b/spec/javascripts/vue_shared/directives/tooltip_spec.js
deleted file mode 100644
index 1d516a280b0..00000000000
--- a/spec/javascripts/vue_shared/directives/tooltip_spec.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import tooltip from '~/vue_shared/directives/tooltip';
-
-describe('Tooltip directive', () => {
- let vm;
-
- afterEach(() => {
- if (vm) {
- vm.$destroy();
- }
- });
-
- describe('with a single tooltip', () => {
- beforeEach(() => {
- setFixtures('<div id="dummy-element"></div>');
- vm = new Vue({
- el: '#dummy-element',
- directives: {
- tooltip,
- },
- data() {
- return {
- tooltip: 'some text',
- };
- },
- template: '<div v-tooltip :title="tooltip"></div>',
- });
- });
-
- it('should have tooltip plugin applied', () => {
- expect($(vm.$el).data('bs.tooltip')).toBeDefined();
- });
-
- it('displays the title as tooltip', () => {
- $(vm.$el).tooltip('show');
- const tooltipElement = document.querySelector('.tooltip-inner');
-
- expect(tooltipElement.innerText).toContain('some text');
- });
-
- it('updates a visible tooltip', done => {
- $(vm.$el).tooltip('show');
- const tooltipElement = document.querySelector('.tooltip-inner');
-
- vm.tooltip = 'other text';
-
- Vue.nextTick()
- .then(() => {
- expect(tooltipElement).toContainText('other text');
- done();
- })
- .catch(done.fail);
- });
- });
-
- describe('with multiple tooltips', () => {
- beforeEach(() => {
- const SomeComponent = Vue.extend({
- directives: {
- tooltip,
- },
- template: `
- <div>
- <div
- v-tooltip
- class="js-look-for-tooltip"
- title="foo">
- </div>
- <div
- v-tooltip
- title="bar">
- </div>
- </div>
- `,
- });
-
- vm = new SomeComponent().$mount();
- });
-
- it('should have tooltip plugin applied to all instances', () => {
- expect(
- $(vm.$el)
- .find('.js-look-for-tooltip')
- .data('bs.tooltip'),
- ).toBeDefined();
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/translate_spec.js b/spec/javascripts/vue_shared/translate_spec.js
deleted file mode 100644
index adca7cd64a1..00000000000
--- a/spec/javascripts/vue_shared/translate_spec.js
+++ /dev/null
@@ -1,251 +0,0 @@
-import Vue from 'vue';
-import Jed from 'jed';
-
-import { trimText } from 'spec/helpers/text_helper';
-import locale from '~/locale';
-import Translate from '~/vue_shared/translate';
-
-describe('Vue translate filter', () => {
- let el;
-
- const createTranslationMock = (key, ...translations) => {
- const fakeLocale = new Jed({
- domain: 'app',
- locale_data: {
- app: {
- '': {
- domain: 'app',
- lang: 'vo',
- plural_forms: 'nplurals=2; plural=(n != 1);',
- },
- [key]: translations,
- },
- },
- });
-
- // eslint-disable-next-line no-underscore-dangle
- locale.__Rewire__('locale', fakeLocale);
- };
-
- afterEach(() => {
- // eslint-disable-next-line no-underscore-dangle
- locale.__ResetDependency__('locale');
- });
-
- beforeEach(() => {
- Vue.use(Translate);
-
- el = document.createElement('div');
-
- document.body.appendChild(el);
- });
-
- it('translate singular text (`__`)', done => {
- const key = 'singular';
- const translation = 'singular_translated';
- createTranslationMock(key, translation);
-
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ __('${key}') }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(translation);
-
- done();
- });
- });
-
- it('translate plural text (`n__`) without any substituting text', done => {
- const key = 'plural';
- const translationPlural = 'plural_multiple translation';
- createTranslationMock(key, 'plural_singular translation', translationPlural);
-
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ n__('${key}', 'plurals', 2) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(translationPlural);
-
- done();
- });
- });
-
- describe('translate plural text (`n__`) with substituting %d', () => {
- const key = '%d day';
-
- beforeEach(() => {
- createTranslationMock(key, '%d singular translated', '%d plural translated');
- });
-
- it('and n === 1', done => {
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ n__('${key}', '%d days', 1) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe('1 singular translated');
-
- done();
- });
- });
-
- it('and n > 1', done => {
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ n__('${key}', '%d days', 2) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe('2 plural translated');
-
- done();
- });
- });
- });
-
- describe('translates text with context `s__`', () => {
- const key = 'Context|Foobar';
- const translation = 'Context|Foobar translated';
- const expectation = 'Foobar translated';
-
- beforeEach(() => {
- createTranslationMock(key, translation);
- });
-
- it('and using two parameters', done => {
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ s__('Context', 'Foobar') }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(expectation);
-
- done();
- });
- });
-
- it('and using the pipe syntax', done => {
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ s__('${key}') }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(expectation);
-
- done();
- });
- });
- });
-
- it('translate multi line text', done => {
- const translation = 'multiline string translated';
- createTranslationMock('multiline string', translation);
-
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ __(\`
- multiline
- string
- \`) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(translation);
-
- done();
- });
- });
-
- it('translate pluralized multi line text', done => {
- const translation = 'multiline string plural';
-
- createTranslationMock('multiline string', 'multiline string singular', translation);
-
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ n__(
- \`
- multiline
- string
- \`,
- \`
- multiline
- strings
- \`,
- 2
- ) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(translation);
-
- done();
- });
- });
-
- it('translate pluralized multi line text with context', done => {
- const translation = 'multiline string with context';
-
- createTranslationMock('Context| multiline string', translation);
-
- const vm = new Vue({
- el,
- template: `
- <span>
- {{ s__(
- \`
- Context|
- multiline
- string
- \`
- ) }}
- </span>
- `,
- }).$mount();
-
- Vue.nextTick(() => {
- expect(trimText(vm.$el.textContent)).toBe(translation);
-
- done();
- });
- });
-});
diff --git a/spec/javascripts/vuex_shared/modules/modal/actions_spec.js b/spec/javascripts/vuex_shared/modules/modal/actions_spec.js
deleted file mode 100644
index 2c4cb845424..00000000000
--- a/spec/javascripts/vuex_shared/modules/modal/actions_spec.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import testAction from 'spec/helpers/vuex_action_helper';
-import * as types from '~/vuex_shared/modules/modal/mutation_types';
-import * as actions from '~/vuex_shared/modules/modal/actions';
-
-describe('Vuex ModalModule actions', () => {
- describe('open', () => {
- it('works', done => {
- const data = { id: 7 };
-
- testAction(actions.open, data, {}, [{ type: types.OPEN, payload: data }], [], done);
- });
- });
-
- describe('close', () => {
- it('works', done => {
- testAction(actions.close, null, {}, [{ type: types.CLOSE }], [], done);
- });
- });
-
- describe('show', () => {
- it('works', done => {
- testAction(actions.show, null, {}, [{ type: types.SHOW }], [], done);
- });
- });
-
- describe('hide', () => {
- it('works', done => {
- testAction(actions.hide, null, {}, [{ type: types.HIDE }], [], done);
- });
- });
-});
diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js
deleted file mode 100644
index 5dee11b3810..00000000000
--- a/spec/javascripts/zen_mode_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import $ from 'jquery';
-import Dropzone from 'dropzone';
-import Mousetrap from 'mousetrap';
-import ZenMode from '~/zen_mode';
-import initNotes from '~/init_notes';
-
-describe('ZenMode', () => {
- let zen;
- let dropzoneForElementSpy;
- const fixtureName = 'snippets/show.html';
-
- preloadFixtures(fixtureName);
-
- function enterZen() {
- $('.notes-form .js-zen-enter').click();
- }
-
- function exitZen() {
- $('.notes-form .js-zen-leave').click();
- }
-
- function escapeKeydown() {
- $('.notes-form textarea').trigger(
- $.Event('keydown', {
- keyCode: 27,
- }),
- );
- }
-
- beforeEach(() => {
- loadFixtures(fixtureName);
- initNotes();
-
- dropzoneForElementSpy = spyOn(Dropzone, 'forElement').and.callFake(() => ({
- enable: () => true,
- }));
- zen = new ZenMode();
-
- // Set this manually because we can't actually scroll the window
- zen.scroll_position = 456;
- });
-
- describe('enabling dropzone', () => {
- beforeEach(() => {
- enterZen();
- });
-
- it('should not call dropzone if element is not dropzone valid', () => {
- $('.div-dropzone').addClass('js-invalid-dropzone');
- exitZen();
-
- expect(dropzoneForElementSpy.calls.count()).toEqual(0);
- });
-
- it('should call dropzone if element is dropzone valid', () => {
- $('.div-dropzone').removeClass('js-invalid-dropzone');
- exitZen();
-
- expect(dropzoneForElementSpy.calls.count()).toEqual(2);
- });
- });
-
- describe('on enter', () => {
- it('pauses Mousetrap', () => {
- const mouseTrapPauseSpy = spyOn(Mousetrap, 'pause');
- enterZen();
-
- expect(mouseTrapPauseSpy).toHaveBeenCalled();
- });
-
- it('removes textarea styling', () => {
- $('.notes-form textarea').attr('style', 'height: 400px');
- enterZen();
-
- expect($('.notes-form textarea')).not.toHaveAttr('style');
- });
- });
-
- describe('in use', () => {
- beforeEach(enterZen);
-
- it('exits on Escape', () => {
- escapeKeydown();
-
- expect($('.notes-form .zen-backdrop')).not.toHaveClass('fullscreen');
- });
- });
-
- describe('on exit', () => {
- beforeEach(enterZen);
-
- it('unpauses Mousetrap', () => {
- const mouseTrapUnpauseSpy = spyOn(Mousetrap, 'unpause');
- exitZen();
-
- expect(mouseTrapUnpauseSpy).toHaveBeenCalled();
- });
-
- it('restores the scroll position', () => {
- spyOn(zen, 'scrollTo');
- exitZen();
-
- expect(zen.scrollTo).toHaveBeenCalled();
- });
- });
-});