summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-05 00:07:50 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-05 00:07:50 +0000
commit54cbcea92909e69248abc9e6b92c7d14db3308a5 (patch)
tree1276f1c57b5ab1064db7197c2d28a8837d68d02d /spec
parent71221554dd9ddf30f73035c89f78164e001aa96d (diff)
downloadgitlab-ce-54cbcea92909e69248abc9e6b92c7d14db3308a5.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/releases/list/components/release_block_milestone_info_spec.js179
-rw-r--r--spec/frontend/releases/list/components/release_block_spec.js88
-rw-r--r--spec/frontend/releases/mock_data.js8
-rw-r--r--spec/lib/gitlab/throttle_spec.rb87
-rw-r--r--spec/requests/rack_attack_global_spec.rb12
5 files changed, 327 insertions, 47 deletions
diff --git a/spec/frontend/releases/list/components/release_block_milestone_info_spec.js b/spec/frontend/releases/list/components/release_block_milestone_info_spec.js
new file mode 100644
index 00000000000..c7d1bc3c372
--- /dev/null
+++ b/spec/frontend/releases/list/components/release_block_milestone_info_spec.js
@@ -0,0 +1,179 @@
+import { mount } from '@vue/test-utils';
+import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
+import ReleaseBlockMilestoneInfo from '~/releases/list/components/release_block_milestone_info.vue';
+import { milestones } from '../../mock_data';
+import { trimText } from 'helpers/text_helper';
+import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/list/constants';
+
+describe('Release block milestone info', () => {
+ let wrapper;
+ let milestonesClone;
+
+ const factory = milestonesProp => {
+ wrapper = mount(ReleaseBlockMilestoneInfo, {
+ propsData: {
+ milestones: milestonesProp,
+ },
+ sync: false,
+ });
+
+ return wrapper.vm.$nextTick();
+ };
+
+ beforeEach(() => {
+ milestonesClone = JSON.parse(JSON.stringify(milestones));
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container');
+ const milestoneListContainer = () => wrapper.find('.js-milestone-list-container');
+ const issuesContainer = () => wrapper.find('.js-issues-container');
+
+ describe('with default props', () => {
+ beforeEach(() => factory(milestonesClone));
+
+ it('renders the correct percentage', () => {
+ expect(milestoneProgressBarContainer().text()).toContain('41% complete');
+ });
+
+ it('renders a progress bar that displays the correct percentage', () => {
+ const progressBar = milestoneProgressBarContainer().find(GlProgressBar);
+
+ expect(progressBar.exists()).toBe(true);
+ expect(progressBar.attributes()).toEqual(
+ expect.objectContaining({
+ value: '22',
+ max: '54',
+ }),
+ );
+ });
+
+ it('renders a list of links to all associated milestones', () => {
+ expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
+
+ milestonesClone.forEach((m, i) => {
+ const milestoneLink = milestoneListContainer()
+ .findAll(GlLink)
+ .at(i);
+
+ expect(milestoneLink.text()).toBe(m.title);
+ expect(milestoneLink.attributes('href')).toBe(m.web_url);
+ expect(milestoneLink.attributes('data-original-title')).toBe(m.description);
+ });
+ });
+
+ it('renders the "Issues" section with a total count of issues associated to the milestone(s)', () => {
+ const totalIssueCount = 54;
+ const issuesContainerText = trimText(issuesContainer().text());
+
+ expect(issuesContainerText).toContain(`Issues ${totalIssueCount}`);
+
+ const badge = issuesContainer().find(GlBadge);
+ expect(badge.text()).toBe(totalIssueCount.toString());
+
+ expect(issuesContainerText).toContain('Open: 32 • Closed: 22');
+ });
+ });
+
+ describe('with lots of milestones', () => {
+ let lotsOfMilestones;
+ let fullListString;
+ let abbreviatedListString;
+
+ beforeEach(() => {
+ lotsOfMilestones = [];
+ const template = milestonesClone[0];
+
+ for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) {
+ lotsOfMilestones.push({
+ ...template,
+ id: template.id + i,
+ iid: template.iid + i,
+ title: `m-${i}`,
+ });
+ }
+
+ fullListString = lotsOfMilestones.map(m => m.title).join(' • ');
+ abbreviatedListString = lotsOfMilestones
+ .slice(0, MAX_MILESTONES_TO_DISPLAY)
+ .map(m => m.title)
+ .join(' • ');
+
+ return factory(lotsOfMilestones);
+ });
+
+ const clickShowMoreFewerButton = () => {
+ milestoneListContainer()
+ .find(GlButton)
+ .trigger('click');
+
+ return wrapper.vm.$nextTick();
+ };
+
+ const milestoneListText = () => trimText(milestoneListContainer().text());
+
+ it('only renders a subset of the milestones', () => {
+ expect(milestoneListText()).toContain(`Milestones ${abbreviatedListString} • show 10 more`);
+ });
+
+ it('renders all milestones when "show more" is clicked', () =>
+ clickShowMoreFewerButton().then(() => {
+ expect(milestoneListText()).toContain(`Milestones ${fullListString} • show fewer`);
+ }));
+
+ it('returns to the original view when "show fewer" is clicked', () =>
+ clickShowMoreFewerButton()
+ .then(clickShowMoreFewerButton)
+ .then(() => {
+ expect(milestoneListText()).toContain(
+ `Milestones ${abbreviatedListString} • show 10 more`,
+ );
+ }));
+ });
+
+ const expectAllZeros = () => {
+ it('displays percentage as 0%', () => {
+ expect(milestoneProgressBarContainer().text()).toContain('0% complete');
+ });
+
+ it('shows 0 for all issue counts', () => {
+ const issuesContainerText = trimText(issuesContainer().text());
+
+ expect(issuesContainerText).toContain('Issues 0 Open: 0 • Closed: 0');
+ });
+ };
+
+ /** Ensures we don't have any issues with dividing by zero when computing percentages */
+ describe('when all issue counts are zero', () => {
+ beforeEach(() => {
+ milestonesClone = milestonesClone.map(m => ({
+ ...m,
+ issue_stats: {
+ ...m.issue_stats,
+ opened: 0,
+ closed: 0,
+ },
+ }));
+
+ return factory(milestonesClone);
+ });
+
+ expectAllZeros();
+ });
+
+ describe('if the API response is missing the "issue_stats" property', () => {
+ beforeEach(() => {
+ milestonesClone = milestonesClone.map(m => ({
+ ...m,
+ issue_stats: undefined,
+ }));
+
+ return factory(milestonesClone);
+ });
+
+ expectAllZeros();
+ });
+});
diff --git a/spec/frontend/releases/list/components/release_block_spec.js b/spec/frontend/releases/list/components/release_block_spec.js
index 056835bdaf2..c7a1cbdea17 100644
--- a/spec/frontend/releases/list/components/release_block_spec.js
+++ b/spec/frontend/releases/list/components/release_block_spec.js
@@ -117,35 +117,6 @@ describe('Release block', () => {
});
});
- it('renders the milestone icon', () => {
- expect(
- milestoneListLabel()
- .find(Icon)
- .exists(),
- ).toBe(true);
- });
-
- it('renders the label as "Milestones" if more than one milestone is passed in', () => {
- expect(
- milestoneListLabel()
- .find('.js-label-text')
- .text(),
- ).toEqual('Milestones');
- });
-
- it('renders a link to the milestone with a tooltip', () => {
- const milestone = first(release.milestones);
- const milestoneLink = wrapper.find('.js-milestone-link');
-
- expect(milestoneLink.exists()).toBe(true);
-
- expect(milestoneLink.text()).toBe(milestone.title);
-
- expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
-
- expect(milestoneLink.attributes('data-original-title')).toBe(milestone.description);
- });
-
it('renders the footer', () => {
expect(wrapper.find(ReleaseBlockFooter).exists()).toBe(true);
});
@@ -187,18 +158,6 @@ describe('Release block', () => {
});
});
- it('renders the label as "Milestone" if only a single milestone is passed in', () => {
- releaseClone.milestones = releaseClone.milestones.slice(0, 1);
-
- return factory(releaseClone).then(() => {
- expect(
- milestoneListLabel()
- .find('.js-label-text')
- .text(),
- ).toEqual('Milestone');
- });
- });
-
it('renders upcoming release badge', () => {
releaseClone.upcoming_release = true;
@@ -281,4 +240,51 @@ describe('Release block', () => {
});
});
});
+
+ describe('when the releaseIssueSummary feature flag is disabled', () => {
+ describe('with default props', () => {
+ beforeEach(() => factory(release, { releaseIssueSummary: false }));
+
+ it('renders the milestone icon', () => {
+ expect(
+ milestoneListLabel()
+ .find(Icon)
+ .exists(),
+ ).toBe(true);
+ });
+
+ it('renders the label as "Milestones" if more than one milestone is passed in', () => {
+ expect(
+ milestoneListLabel()
+ .find('.js-label-text')
+ .text(),
+ ).toEqual('Milestones');
+ });
+
+ it('renders a link to the milestone with a tooltip', () => {
+ const milestone = first(release.milestones);
+ const milestoneLink = wrapper.find('.js-milestone-link');
+
+ expect(milestoneLink.exists()).toBe(true);
+
+ expect(milestoneLink.text()).toBe(milestone.title);
+
+ expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
+
+ expect(milestoneLink.attributes('data-original-title')).toBe(milestone.description);
+ });
+ });
+
+ it('renders the label as "Milestone" if only a single milestone is passed in', () => {
+ releaseClone.milestones = releaseClone.milestones.slice(0, 1);
+
+ return factory(releaseClone, { releaseIssueSummary: false }).then(() => {
+ expect(
+ milestoneListLabel()
+ .find('.js-label-text')
+ .text(),
+ ).toEqual('Milestone');
+ });
+ });
+ });
});
diff --git a/spec/frontend/releases/mock_data.js b/spec/frontend/releases/mock_data.js
index e1830b494bc..630f14d3a73 100644
--- a/spec/frontend/releases/mock_data.js
+++ b/spec/frontend/releases/mock_data.js
@@ -11,6 +11,10 @@ export const milestones = [
due_date: '2019-09-19',
start_date: '2019-08-31',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2',
+ issue_stats: {
+ opened: 14,
+ closed: 19,
+ },
},
{
id: 49,
@@ -24,6 +28,10 @@ export const milestones = [
due_date: '2019-10-11',
start_date: '2019-08-19',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1',
+ issue_stats: {
+ opened: 18,
+ closed: 3,
+ },
},
];
diff --git a/spec/lib/gitlab/throttle_spec.rb b/spec/lib/gitlab/throttle_spec.rb
new file mode 100644
index 00000000000..674646a5f06
--- /dev/null
+++ b/spec/lib/gitlab/throttle_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Throttle do
+ describe '.protected_paths_enabled?' do
+ subject { described_class.protected_paths_enabled? }
+
+ context 'when omnibus protected paths throttle should be used' do
+ before do
+ expect(described_class).to receive(:should_use_omnibus_protected_paths?).and_return(true)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when omnibus protected paths throttle should not be used' do
+ before do
+ expect(described_class).to receive(:should_use_omnibus_protected_paths?).and_return(false)
+ end
+
+ it 'returns Application Settings throttle_protected_paths_enabled?' do
+ expect(Gitlab::CurrentSettings.current_application_settings).to receive(:throttle_protected_paths_enabled?)
+
+ subject
+ end
+ end
+ end
+
+ describe '.should_use_omnibus_protected_paths?' do
+ subject { described_class.should_use_omnibus_protected_paths? }
+
+ context 'when rack_attack.admin_area_protected_paths_enabled config is unspecified' do
+ context 'when the omnibus protected paths throttle has been recently used (it has data)' do
+ before do
+ expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the omnibus protected paths throttle has not been recently used' do
+ before do
+ expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when rack_attack.admin_area_protected_paths_enabled config is false' do
+ before do
+ stub_config(rack_attack: {
+ admin_area_protected_paths_enabled: false
+ })
+ end
+
+ context 'when the omnibus protected paths throttle has been recently used (it has data)' do
+ before do
+ expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the omnibus protected paths throttle has not been recently used' do
+ before do
+ expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when rack_attack.admin_area_protected_paths_enabled config is true' do
+ before do
+ stub_config(rack_attack: {
+ admin_area_protected_paths_enabled: true
+ })
+
+ expect(described_class).not_to receive(:omnibus_protected_paths_present?)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 4d5055a7e27..59113687d1c 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -249,10 +249,10 @@ describe 'Rack Attack global throttles' do
expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params }
end
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
before do
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end
it 'allows requests over the rate limit' do
@@ -298,7 +298,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited token-authenticated requests'
end
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
let(:request_args) { [api(api_partial_url, personal_access_token: token)] }
let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token)] }
@@ -309,7 +309,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set)
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end
it 'allows requests over the rate limit' do
@@ -339,7 +339,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited web authenticated requests'
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
before do
settings_to_set[:"#{throttle_setting_prefix}_requests_per_period"] = requests_per_period
settings_to_set[:"#{throttle_setting_prefix}_period_in_seconds"] = period_in_seconds
@@ -347,7 +347,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set)
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
login_as(user)
end