summaryrefslogtreecommitdiff
path: root/spec/frontend/releases/list
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-20 09:07:57 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-20 09:07:57 +0000
commit7881eb30eaa8b01dbcfe87faa09927c75c7d6e45 (patch)
tree298bc8d2c62b2f2c29cb8ecbcf3de3eaaa6466d9 /spec/frontend/releases/list
parent64b66e0cb6d1bfd27abf24e06653f00bddb60597 (diff)
downloadgitlab-ce-7881eb30eaa8b01dbcfe87faa09927c75c7d6e45.tar.gz
Add latest changes from gitlab-org/gitlab@12-6-stable-ee
Diffstat (limited to 'spec/frontend/releases/list')
-rw-r--r--spec/frontend/releases/list/components/evidence_block_spec.js77
-rw-r--r--spec/frontend/releases/list/components/release_block_footer_spec.js12
-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.js119
4 files changed, 332 insertions, 55 deletions
diff --git a/spec/frontend/releases/list/components/evidence_block_spec.js b/spec/frontend/releases/list/components/evidence_block_spec.js
new file mode 100644
index 00000000000..e8a3eace216
--- /dev/null
+++ b/spec/frontend/releases/list/components/evidence_block_spec.js
@@ -0,0 +1,77 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
+import { truncateSha } from '~/lib/utils/text_utility';
+import Icon from '~/vue_shared/components/icon.vue';
+import { release } from '../../mock_data';
+import EvidenceBlock from '~/releases/list/components/evidence_block.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+describe('Evidence Block', () => {
+ let wrapper;
+
+ const factory = (options = {}) => {
+ const localVue = createLocalVue();
+
+ wrapper = mount(localVue.extend(EvidenceBlock), {
+ localVue,
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ factory({
+ propsData: {
+ release,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders the evidence icon', () => {
+ expect(wrapper.find(Icon).props('name')).toBe('review-list');
+ });
+
+ it('renders the title for the dowload link', () => {
+ expect(wrapper.find(GlLink).text()).toBe(`${release.tag_name}-evidence.json`);
+ });
+
+ it('renders the correct hover text for the download', () => {
+ expect(wrapper.find(GlLink).attributes('data-original-title')).toBe('Download evidence JSON');
+ });
+
+ it('renders the correct file link for download', () => {
+ expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tag_name}-evidence.json`);
+ });
+
+ describe('sha text', () => {
+ it('renders the short sha initially', () => {
+ expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidence_sha));
+ });
+
+ it('renders the long sha after expansion', () => {
+ wrapper.find('.js-text-expander-prepend').trigger('click');
+ expect(wrapper.find('.js-expanded').text()).toBe(release.evidence_sha);
+ });
+ });
+
+ describe('copy to clipboard button', () => {
+ it('renders button', () => {
+ expect(wrapper.find(ClipboardButton).exists()).toBe(true);
+ });
+
+ it('renders the correct hover text', () => {
+ expect(wrapper.find(ClipboardButton).attributes('data-original-title')).toBe(
+ 'Copy commit SHA',
+ );
+ });
+
+ it('copies the sha', () => {
+ expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe(
+ release.evidence_sha,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/releases/list/components/release_block_footer_spec.js b/spec/frontend/releases/list/components/release_block_footer_spec.js
index 172147f1cc8..7652acbdd62 100644
--- a/spec/frontend/releases/list/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/list/components/release_block_footer_spec.js
@@ -1,15 +1,15 @@
import { mount } from '@vue/test-utils';
-import ReleaseBlockFooter from '~/releases/list/components/release_block_footer.vue';
-import Icon from '~/vue_shared/components/icon.vue';
import { GlLink } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
+import ReleaseBlockFooter from '~/releases/list/components/release_block_footer.vue';
+import Icon from '~/vue_shared/components/icon.vue';
import { release } from '../../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
jest.mock('~/vue_shared/mixins/timeago', () => ({
methods: {
- timeFormated() {
- return '7 fortnightes ago';
+ timeFormatted() {
+ return '7 fortnights ago';
},
tooltipTitle() {
return 'February 30, 2401';
@@ -82,7 +82,7 @@ describe('Release block footer', () => {
it('renders the author and creation time info', () => {
expect(trimText(authorDateInfoSection().text())).toBe(
- `Created 7 fortnightes ago by ${releaseClone.author.username}`,
+ `Created 7 fortnights ago by ${releaseClone.author.username}`,
);
});
@@ -139,7 +139,7 @@ describe('Release block footer', () => {
beforeEach(() => factory({ author: undefined }));
it('renders the release date without the author name', () => {
- expect(trimText(authorDateInfoSection().text())).toBe('Created 7 fortnightes ago');
+ expect(trimText(authorDateInfoSection().text())).toBe('Created 7 fortnights ago');
});
});
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..7179ab3d3cc
--- /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 { trimText } from 'helpers/text_helper';
+import ReleaseBlockMilestoneInfo from '~/releases/list/components/release_block_milestone_info.vue';
+import { milestones } from '../../mock_data';
+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 b63ef068d8e..38c5e4fc0a2 100644
--- a/spec/frontend/releases/list/components/release_block_spec.js
+++ b/spec/frontend/releases/list/components/release_block_spec.js
@@ -1,8 +1,9 @@
import { mount } from '@vue/test-utils';
+import { first } from 'underscore';
+import EvidenceBlock from '~/releases/list/components/evidence_block.vue';
import ReleaseBlock from '~/releases/list/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/list/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { first } from 'underscore';
import { release } from '../../mock_data';
import Icon from '~/vue_shared/components/icon.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
@@ -29,7 +30,6 @@ describe('Release block', () => {
},
provide: {
glFeatures: {
- releaseEditPage: true,
releaseIssueSummary: true,
...featureFlags,
},
@@ -68,7 +68,7 @@ describe('Release block', () => {
});
it('renders release date', () => {
- expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormated(release.released_at));
+ expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at));
});
it('renders number of assets provided', () => {
@@ -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);
});
@@ -179,11 +150,6 @@ describe('Release block', () => {
});
});
- it('does not render an edit button if the releaseEditPage feature flag is disabled', () =>
- factory(releaseClone, { releaseEditPage: false }).then(() => {
- expect(editButton().exists()).toBe(false);
- }));
-
it('does not render the milestone list if no milestones are associated to the release', () => {
delete releaseClone.milestones;
@@ -192,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;
@@ -220,6 +174,26 @@ describe('Release block', () => {
});
});
+ describe('evidence block', () => {
+ it('renders the evidence block when the evidence is available and the feature flag is true', () =>
+ factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
+ expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
+ ));
+
+ it('does not render the evidence block when the evidence is available but the feature flag is false', () =>
+ factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
+ expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
+ ));
+
+ it('does not render the evidence block when there is no evidence', () => {
+ releaseClone.evidence_sha = null;
+
+ return factory(releaseClone).then(() => {
+ expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
+ });
+ });
+ });
+
describe('anchor scrolling', () => {
beforeEach(() => {
scrollToElement.mockClear();
@@ -266,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');
+ });
+ });
+ });
});