diff options
-rw-r--r-- | app/assets/javascripts/issue.js | 108 | ||||
-rw-r--r-- | app/assets/stylesheets/framework/filters.scss | 2 | ||||
-rw-r--r-- | app/helpers/javascript_helper.rb | 5 | ||||
-rw-r--r-- | app/helpers/webpack_helper.rb | 30 | ||||
-rw-r--r-- | app/views/help/ui.html.haml | 8 | ||||
-rw-r--r-- | app/views/layouts/_head.html.haml | 6 | ||||
-rw-r--r-- | changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml | 4 | ||||
-rw-r--r-- | changelogs/unreleased/27729-improve-webpack-dev-environment.yml | 4 | ||||
-rw-r--r-- | changelogs/unreleased/fix-missing-capitalisation-buttons.yml | 4 | ||||
-rw-r--r-- | changelogs/unreleased/reset-new-branch-button.yml | 4 | ||||
-rw-r--r-- | config/webpack.config.js | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/performance.md | 4 | ||||
-rw-r--r-- | doc/topics/authentication/index.md | 6 | ||||
-rw-r--r-- | doc/topics/index.md | 3 | ||||
-rw-r--r-- | doc/user/project/integrations/kubernetes.md | 2 | ||||
-rw-r--r-- | spec/javascripts/issue_spec.js | 194 |
16 files changed, 234 insertions, 154 deletions
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 47e675f537e..011043e992f 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -20,57 +20,60 @@ class Issue { }); Issue.initIssueBtnEventListeners(); } + + Issue.$btnNewBranch = $('#new-branch'); + Issue.initMergeRequests(); Issue.initRelatedBranches(); Issue.initCanCreateBranch(); } static initIssueBtnEventListeners() { - var issueFailMessage; - issueFailMessage = 'Unable to update this issue at this time.'; - return $('a.btn-close, a.btn-reopen').on('click', function(e) { - var $this, isClose, shouldSubmit, url; + const issueFailMessage = 'Unable to update this issue at this time.'; + + const closeButtons = $('a.btn-close'); + const isClosedBadge = $('div.status-box-closed'); + const isOpenBadge = $('div.status-box-open'); + const projectIssuesCounter = $('.issue_counter'); + const reopenButtons = $('a.btn-reopen'); + + return closeButtons.add(reopenButtons).on('click', function(e) { + var $this, shouldSubmit, url; e.preventDefault(); e.stopImmediatePropagation(); $this = $(this); - isClose = $this.hasClass('btn-close'); shouldSubmit = $this.hasClass('btn-comment'); if (shouldSubmit) { Issue.submitNoteForm($this.closest('form')); } $this.prop('disabled', true); + Issue.setNewBranchButtonState(true, null); url = $this.attr('href'); return $.ajax({ type: 'PUT', - url: url, - error: function(jqXHR, textStatus, errorThrown) { - var issueStatus; - issueStatus = isClose ? 'close' : 'open'; - return new Flash(issueFailMessage, 'alert'); - }, - success: function(data, textStatus, jqXHR) { - if ('id' in data) { - $(document).trigger('issuable:change'); - let total = Number($('.issue_counter').text().replace(/[^\d]/, '')); - if (isClose) { - $('a.btn-close').addClass('hidden'); - $('a.btn-reopen').removeClass('hidden'); - $('div.status-box-closed').removeClass('hidden'); - $('div.status-box-open').addClass('hidden'); - total -= 1; - } else { - $('a.btn-reopen').addClass('hidden'); - $('a.btn-close').removeClass('hidden'); - $('div.status-box-closed').addClass('hidden'); - $('div.status-box-open').removeClass('hidden'); - total += 1; - } - $('.issue_counter').text(gl.text.addDelimiter(total)); - } else { - new Flash(issueFailMessage, 'alert'); - } - return $this.prop('disabled', false); + url: url + }).fail(function(jqXHR, textStatus, errorThrown) { + new Flash(issueFailMessage); + Issue.initCanCreateBranch(); + }).done(function(data, textStatus, jqXHR) { + if ('id' in data) { + $(document).trigger('issuable:change'); + + const isClosed = $this.hasClass('btn-close'); + closeButtons.toggleClass('hidden', isClosed); + reopenButtons.toggleClass('hidden', !isClosed); + isClosedBadge.toggleClass('hidden', !isClosed); + isOpenBadge.toggleClass('hidden', isClosed); + + let numProjectIssues = Number(projectIssuesCounter.text().replace(/[^\d]/, '')); + numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1; + projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues)); + } else { + new Flash(issueFailMessage); } + + $this.prop('disabled', false); + Issue.initCanCreateBranch(); }); }); } @@ -86,9 +89,9 @@ class Issue { static initMergeRequests() { var $container; $container = $('#merge-requests'); - return $.getJSON($container.data('url')).error(function() { - return new Flash('Failed to load referenced merge requests', 'alert'); - }).success(function(data) { + return $.getJSON($container.data('url')).fail(function() { + return new Flash('Failed to load referenced merge requests'); + }).done(function(data) { if ('html' in data) { return $container.html(data.html); } @@ -98,9 +101,9 @@ class Issue { static initRelatedBranches() { var $container; $container = $('#related-branches'); - return $.getJSON($container.data('url')).error(function() { - return new Flash('Failed to load related branches', 'alert'); - }).success(function(data) { + return $.getJSON($container.data('url')).fail(function() { + return new Flash('Failed to load related branches'); + }).done(function(data) { if ('html' in data) { return $container.html(data.html); } @@ -108,24 +111,27 @@ class Issue { } static initCanCreateBranch() { - var $container; - $container = $('#new-branch'); // If the user doesn't have the required permissions the container isn't // rendered at all. - if ($container.length === 0) { + if (Issue.$btnNewBranch.length === 0) { return; } - return $.getJSON($container.data('path')).error(function() { - $container.find('.unavailable').show(); - return new Flash('Failed to check if a new branch can be created.', 'alert'); - }).success(function(data) { - if (data.can_create_branch) { - $container.find('.available').show(); - } else { - return $container.find('.unavailable').show(); - } + return $.getJSON(Issue.$btnNewBranch.data('path')).fail(function() { + Issue.setNewBranchButtonState(false, false); + new Flash('Failed to check if a new branch can be created.'); + }).done(function(data) { + Issue.setNewBranchButtonState(false, data.can_create_branch); }); } + + static setNewBranchButtonState(isPending, canCreate) { + if (Issue.$btnNewBranch.length === 0) { + return; + } + + Issue.$btnNewBranch.find('.available').toggle(!isPending && canCreate); + Issue.$btnNewBranch.find('.unavailable').toggle(!isPending && !canCreate); + } } export default Issue; diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 12465d4a70b..279a50eaa33 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -82,7 +82,7 @@ .input-token:last-child { flex: 1; -webkit-flex: 1; - max-width: initial; + max-width: inherit; } } diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index 68c09c922a6..d5e77c7e271 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -3,7 +3,8 @@ module JavascriptHelper javascript_include_tag asset_path(js) end - def page_specific_javascript_bundle_tag(js) - javascript_include_tag(*webpack_asset_paths(js)) + # deprecated; use webpack_bundle_tag directly instead + def page_specific_javascript_bundle_tag(bundle) + webpack_bundle_tag(bundle) end end diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb new file mode 100644 index 00000000000..6bacda9fe75 --- /dev/null +++ b/app/helpers/webpack_helper.rb @@ -0,0 +1,30 @@ +require 'webpack/rails/manifest' + +module WebpackHelper + def webpack_bundle_tag(bundle) + javascript_include_tag(*gitlab_webpack_asset_paths(bundle)) + end + + # override webpack-rails gem helper until changes can make it upstream + def gitlab_webpack_asset_paths(source, extension: nil) + return "" unless source.present? + + paths = Webpack::Rails::Manifest.asset_paths(source) + if extension + paths = paths.select { |p| p.ends_with? ".#{extension}" } + end + + # include full webpack-dev-server url for rspec tests running locally + if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled + host = Rails.configuration.webpack.dev_server.host + port = Rails.configuration.webpack.dev_server.port + protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http' + + paths.map! do |p| + "#{protocol}://#{host}:#{port}#{p}" + end + end + + paths + end +end diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 207f80bedfe..615dd56afbd 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -252,7 +252,7 @@ = icon('chevron-down') .dropdown-menu.dropdown-select.dropdown-menu-selectable .dropdown-title - %span Dropdown Title + %span Dropdown title %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } = icon('times') .dropdown-input @@ -291,7 +291,7 @@ = icon('chevron-down') .dropdown-menu.dropdown-select.dropdown-menu-selectable.is-loading .dropdown-title - %span Dropdown Title + %span Dropdown title %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } = icon('times') .dropdown-input @@ -335,7 +335,7 @@ = icon('chevron-down') .dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-user .dropdown-title - %span Dropdown Title + %span Dropdown title %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } = icon('times') .dropdown-input @@ -362,7 +362,7 @@ .dropdown-title %button.dropdown-title-button.dropdown-menu-back{ aria: { label: "Go back" } } = icon('arrow-left') - %span Dropdown Title + %span Dropdown title %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } = icon('times') .dropdown-input diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index a611481a0a4..19473b6ab27 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -28,9 +28,9 @@ = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" - = javascript_include_tag(*webpack_asset_paths("runtime")) - = javascript_include_tag(*webpack_asset_paths("common")) - = javascript_include_tag(*webpack_asset_paths("main")) + = webpack_bundle_tag "runtime" + = webpack_bundle_tag "common" + = webpack_bundle_tag "main" - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml b/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml new file mode 100644 index 00000000000..706609b7baf --- /dev/null +++ b/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml @@ -0,0 +1,4 @@ +--- +title: Fix filtered search input width for IE +merge_request: +author: diff --git a/changelogs/unreleased/27729-improve-webpack-dev-environment.yml b/changelogs/unreleased/27729-improve-webpack-dev-environment.yml new file mode 100644 index 00000000000..d04ea70ab1c --- /dev/null +++ b/changelogs/unreleased/27729-improve-webpack-dev-environment.yml @@ -0,0 +1,4 @@ +--- +title: Add webpack_bundle_tag helper to improve non-localhost GDK configurations +merge_request: 10604 +author: diff --git a/changelogs/unreleased/fix-missing-capitalisation-buttons.yml b/changelogs/unreleased/fix-missing-capitalisation-buttons.yml new file mode 100644 index 00000000000..b2c40483475 --- /dev/null +++ b/changelogs/unreleased/fix-missing-capitalisation-buttons.yml @@ -0,0 +1,4 @@ +--- +title: Fix missing capitalisation on views +merge_request: +author: diff --git a/changelogs/unreleased/reset-new-branch-button.yml b/changelogs/unreleased/reset-new-branch-button.yml new file mode 100644 index 00000000000..318ee46298f --- /dev/null +++ b/changelogs/unreleased/reset-new-branch-button.yml @@ -0,0 +1,4 @@ +--- +title: Reset New branch button when issue state changes +merge_request: 5962 +author: winniehell diff --git a/config/webpack.config.js b/config/webpack.config.js index 0fea3f8222b..ffb16190093 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -11,6 +11,7 @@ var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeMod var ROOT_PATH = path.resolve(__dirname, '..'); var IS_PRODUCTION = process.env.NODE_ENV === 'production'; var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; +var DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost'; var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808; var DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false'; var WEBPACK_REPORT = process.env.WEBPACK_REPORT; @@ -182,12 +183,13 @@ if (IS_PRODUCTION) { if (IS_DEV_SERVER) { config.devtool = 'cheap-module-eval-source-map'; config.devServer = { + host: DEV_SERVER_HOST, port: DEV_SERVER_PORT, headers: { 'Access-Control-Allow-Origin': '*' }, stats: 'errors-only', inline: DEV_SERVER_LIVERELOAD }; - config.output.publicPath = '//localhost:' + DEV_SERVER_PORT + config.output.publicPath; + config.output.publicPath = '//' + DEV_SERVER_HOST + ':' + DEV_SERVER_PORT + config.output.publicPath; config.plugins.push( // watch node_modules for changes if we encounter a missing module compile error new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules')) diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index e74eb729515..2ddcbe13afa 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -48,8 +48,8 @@ Steps to split page-specific JavaScript from the main `main.js`: ```haml - content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('lib_chart') - = page_specific_javascript_bundle_tag('graphs') + = webpack_bundle_tag 'lib_chart' + = webpack_bundle_tag 'graphs' ``` The above loads `chart.js` and `graphs_bundle.js` for this page only. `chart.js` diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md index 47d3f05999d..eafd2fd9d04 100644 --- a/doc/topics/authentication/index.md +++ b/doc/topics/authentication/index.md @@ -15,11 +15,11 @@ This page gathers all the resources for the topic **Authentication** within GitL ## GitLab administrators - [LDAP (Community Edition)](../../administration/auth/ldap.md) -- [LDAP (Enterprise Edition)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.md) +- [LDAP (Enterprise Edition)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html) - [Enforce Two-factor Authentication (2FA)](../../security/two_factor_authentication.md#enforce-two-factor-authentication-2fa) - **Articles:** - [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/) - - [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/ldap/debugging_ldap.md) + - [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/ldap/debugging_ldap.html) - **Integrations:** - [OmniAuth](../../integration/omniauth.md) - [Authentiq OmniAuth Provider](../../administration/auth/authentiq.md#authentiq-omniauth-provider) @@ -27,7 +27,7 @@ This page gathers all the resources for the topic **Authentication** within GitL - [CAS OmniAuth Provider](../../integration/cas.md) - [SAML OmniAuth Provider](../../integration/saml.md) - [Okta SSO provider](../../administration/auth/okta.md) - - [Kerberos integration (GitLab EE)](https://docs.gitlab.com/ee/integration/kerberos.md) + - [Kerberos integration (GitLab EE)](https://docs.gitlab.com/ee/integration/kerberos.html) ## API diff --git a/doc/topics/index.md b/doc/topics/index.md index 4a16f6f629c..ad388dff822 100644 --- a/doc/topics/index.md +++ b/doc/topics/index.md @@ -7,9 +7,10 @@ you through better understanding GitLab's concepts through our regular docs, and, when available, through articles (guides, tutorials, technical overviews, blog posts) and videos. +- [Authentication](authentication/index.md) - [Continuous Integration (GitLab CI)](../ci/README.md) - [Git](git/index.md) - [GitLab Installation](../install/README.md) - [GitLab Pages](../user/project/pages/index.md) ->**Note:** More topics will be available soon.
\ No newline at end of file +>**Note:** More topics will be available soon. diff --git a/doc/user/project/integrations/kubernetes.md b/doc/user/project/integrations/kubernetes.md index 2a890acde4d..f7d5e3a8ab2 100644 --- a/doc/user/project/integrations/kubernetes.md +++ b/doc/user/project/integrations/kubernetes.md @@ -60,7 +60,7 @@ to use terminals. Support is currently limited to the first container in the first pod of your environment. When enabled, the Kubernetes service adds [web terminal](../../../ci/environments.md#web-terminals) -support to your environments. This is based on the `exec` functionality found in +support to your [environments](../../../ci/environments.md). This is based on the `exec` functionality found in Docker and Kubernetes, so you get a new shell session within your existing containers. To use this integration, you should deploy to Kubernetes using the deployment variables above, ensuring any pods you create are labelled with diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index aabc8bea12f..9a2570ef7e9 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,18 +1,17 @@ -/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */ +/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */ import Issue from '~/issue'; require('~/lib/utils/text_utility'); describe('Issue', function() { - var INVALID_URL = 'http://goesnowhere.nothing/whereami'; - var $boxClosed, $boxOpen, $btnClose, $btnReopen; + let $boxClosed, $boxOpen, $btnClose, $btnReopen; preloadFixtures('issues/closed-issue.html.raw'); preloadFixtures('issues/issue-with-task-list.html.raw'); preloadFixtures('issues/open-issue.html.raw'); function expectErrorMessage() { - var $flashMessage = $('div.flash-alert'); + const $flashMessage = $('div.flash-alert'); expect($flashMessage).toExist(); expect($flashMessage).toBeVisible(); expect($flashMessage).toHaveText('Unable to update this issue at this time.'); @@ -26,10 +25,28 @@ describe('Issue', function() { expectVisibility($btnReopen, !isIssueOpen); } - function expectPendingRequest(req, $triggeredButton) { - expect(req.type).toBe('PUT'); - expect(req.url).toBe($triggeredButton.attr('href')); - expect($triggeredButton).toHaveProp('disabled', true); + function expectNewBranchButtonState(isPending, canCreate) { + if (Issue.$btnNewBranch.length === 0) { + return; + } + + const $available = Issue.$btnNewBranch.find('.available'); + expect($available).toHaveText('New branch'); + + if (!isPending && canCreate) { + expect($available).toBeVisible(); + } else { + expect($available).toBeHidden(); + } + + const $unavailable = Issue.$btnNewBranch.find('.unavailable'); + expect($unavailable).toHaveText('New branch unavailable'); + + if (!isPending && !canCreate) { + expect($unavailable).toBeVisible(); + } else { + expect($unavailable).toBeHidden(); + } } function expectVisibility($element, shouldBeVisible) { @@ -81,100 +98,107 @@ describe('Issue', function() { }); }); - describe('close issue', function() { - beforeEach(function() { - loadFixtures('issues/open-issue.html.raw'); - findElements(); - this.issue = new Issue(); - - expectIssueState(true); - }); + [true, false].forEach((isIssueInitiallyOpen) => { + describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, function() { + const action = isIssueInitiallyOpen ? 'close' : 'reopen'; + + function ajaxSpy(req) { + if (req.url === this.$triggeredButton.attr('href')) { + expect(req.type).toBe('PUT'); + expect(this.$triggeredButton).toHaveProp('disabled', true); + expectNewBranchButtonState(true, false); + return this.issueStateDeferred; + } else if (req.url === Issue.$btnNewBranch.data('path')) { + expect(req.type).toBe('get'); + expectNewBranchButtonState(true, false); + return this.canCreateBranchDeferred; + } + + expect(req.url).toBe('unexpected'); + return null; + } + + beforeEach(function() { + if (isIssueInitiallyOpen) { + loadFixtures('issues/open-issue.html.raw'); + } else { + loadFixtures('issues/closed-issue.html.raw'); + } + + findElements(); + this.issue = new Issue(); + expectIssueState(isIssueInitiallyOpen); + this.$triggeredButton = isIssueInitiallyOpen ? $btnClose : $btnReopen; + + this.$projectIssuesCounter = $('.issue_counter'); + this.$projectIssuesCounter.text('1,001'); + + this.issueStateDeferred = new jQuery.Deferred(); + this.canCreateBranchDeferred = new jQuery.Deferred(); + + spyOn(jQuery, 'ajax').and.callFake(ajaxSpy.bind(this)); + }); - it('closes an issue', function() { - spyOn(jQuery, 'ajax').and.callFake(function(req) { - expectPendingRequest(req, $btnClose); - req.success({ + it(`${action}s the issue`, function() { + this.$triggeredButton.trigger('click'); + this.issueStateDeferred.resolve({ id: 34 }); - }); - - $btnClose.trigger('click'); + this.canCreateBranchDeferred.resolve({ + can_create_branch: !isIssueInitiallyOpen + }); - expectIssueState(false); - expect($btnClose).toHaveProp('disabled', false); - expect($('.issue_counter')).toHaveText(0); - }); + expectIssueState(!isIssueInitiallyOpen); + expect(this.$triggeredButton).toHaveProp('disabled', false); + expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002'); + expectNewBranchButtonState(false, !isIssueInitiallyOpen); + }); - it('fails to close an issue with success:false', function() { - spyOn(jQuery, 'ajax').and.callFake(function(req) { - expectPendingRequest(req, $btnClose); - req.success({ + it(`fails to ${action} the issue if saved:false`, function() { + this.$triggeredButton.trigger('click'); + this.issueStateDeferred.resolve({ saved: false }); - }); - - $btnClose.attr('href', INVALID_URL); - $btnClose.trigger('click'); - - expectIssueState(true); - expect($btnClose).toHaveProp('disabled', false); - expectErrorMessage(); - expect($('.issue_counter')).toHaveText(1); - }); + this.canCreateBranchDeferred.resolve({ + can_create_branch: isIssueInitiallyOpen + }); - it('fails to closes an issue with HTTP error', function() { - spyOn(jQuery, 'ajax').and.callFake(function(req) { - expectPendingRequest(req, $btnClose); - req.error(); + expectIssueState(isIssueInitiallyOpen); + expect(this.$triggeredButton).toHaveProp('disabled', false); + expectErrorMessage(); + expect(this.$projectIssuesCounter.text()).toBe('1,001'); + expectNewBranchButtonState(false, isIssueInitiallyOpen); }); - $btnClose.attr('href', INVALID_URL); - $btnClose.trigger('click'); - - expectIssueState(true); - expect($btnClose).toHaveProp('disabled', true); - expectErrorMessage(); - expect($('.issue_counter')).toHaveText(1); - }); - - it('updates counter', () => { - spyOn(jQuery, 'ajax').and.callFake(function(req) { - expectPendingRequest(req, $btnClose); - req.success({ - id: 34 + it(`fails to ${action} the issue if HTTP error occurs`, function() { + this.$triggeredButton.trigger('click'); + this.issueStateDeferred.reject(); + this.canCreateBranchDeferred.resolve({ + can_create_branch: isIssueInitiallyOpen }); - }); - expect($('.issue_counter')).toHaveText(1); - $('.issue_counter').text('1,001'); - expect($('.issue_counter').text()).toEqual('1,001'); - $btnClose.trigger('click'); - expect($('.issue_counter').text()).toEqual('1,000'); - }); - }); + expectIssueState(isIssueInitiallyOpen); + expect(this.$triggeredButton).toHaveProp('disabled', true); + expectErrorMessage(); + expect(this.$projectIssuesCounter.text()).toBe('1,001'); + expectNewBranchButtonState(false, isIssueInitiallyOpen); + }); - describe('reopen issue', function() { - beforeEach(function() { - loadFixtures('issues/closed-issue.html.raw'); - findElements(); - this.issue = new Issue(); + it('disables the new branch button if Ajax call fails', function() { + this.$triggeredButton.trigger('click'); + this.issueStateDeferred.reject(); + this.canCreateBranchDeferred.reject(); - expectIssueState(false); - }); - - it('reopens an issue', function() { - spyOn(jQuery, 'ajax').and.callFake(function(req) { - expectPendingRequest(req, $btnReopen); - req.success({ - id: 34 - }); + expectNewBranchButtonState(false, false); }); - $btnReopen.trigger('click'); + it('does not trigger Ajax call if new branch button is missing', function() { + Issue.$btnNewBranch = $(); + this.canCreateBranchDeferred = null; - expectIssueState(true); - expect($btnReopen).toHaveProp('disabled', false); - expect($('.issue_counter')).toHaveText(1); + this.$triggeredButton.trigger('click'); + this.issueStateDeferred.reject(); + }); }); }); }); |