Commit 4b9ff9d1 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'nfriend-camel-case-releases' into 'master'

Reference all Release data using `camelCase`

See merge request gitlab-org/gitlab!24700
parents db447fd8 95fcaa50
...@@ -76,7 +76,7 @@ export default { ...@@ -76,7 +76,7 @@ export default {
<div v-else-if="shouldRenderSuccessState" class="js-success-state"> <div v-else-if="shouldRenderSuccessState" class="js-success-state">
<release-block <release-block
v-for="(release, index) in releases" v-for="(release, index) in releases"
:key="release.tag_name" :key="release.tagName"
:release="release" :release="release"
:class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }"
/> />
......
...@@ -25,16 +25,16 @@ export default { ...@@ -25,16 +25,16 @@ export default {
}, },
computed: { computed: {
evidenceTitle() { evidenceTitle() {
return sprintf(__('%{tag}-evidence.json'), { tag: this.release.tag_name }); return sprintf(__('%{tag}-evidence.json'), { tag: this.release.tagName });
}, },
evidenceUrl() { evidenceUrl() {
return this.release.assets && this.release.assets.evidence_file_path; return this.release.assets && this.release.assets.evidenceFilePath;
}, },
shortSha() { shortSha() {
return truncateSha(this.sha); return truncateSha(this.sha);
}, },
sha() { sha() {
return this.release.evidence_sha; return this.release.evidenceSha;
}, },
}, },
}; };
......
...@@ -38,13 +38,13 @@ export default { ...@@ -38,13 +38,13 @@ export default {
}, },
computed: { computed: {
id() { id() {
return slugify(this.release.tag_name); return slugify(this.release.tagName);
}, },
assets() { assets() {
return this.release.assets || {}; return this.release.assets || {};
}, },
hasEvidence() { hasEvidence() {
return Boolean(this.release.evidence_sha); return Boolean(this.release.evidenceSha);
}, },
milestones() { milestones() {
return this.release.milestones || []; return this.release.milestones || [];
...@@ -102,7 +102,7 @@ export default { ...@@ -102,7 +102,7 @@ export default {
<evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" /> <evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" />
<div ref="gfm-content" class="card-text prepend-top-default"> <div ref="gfm-content" class="card-text prepend-top-default">
<div v-html="release.description_html"></div> <div v-html="release.descriptionHtml"></div>
</div> </div>
</div> </div>
...@@ -110,11 +110,11 @@ export default { ...@@ -110,11 +110,11 @@ export default {
v-if="shouldShowFooter" v-if="shouldShowFooter"
class="card-footer" class="card-footer"
:commit="release.commit" :commit="release.commit"
:commit-path="release.commit_path" :commit-path="release.commitPath"
:tag-name="release.tag_name" :tag-name="release.tagName"
:tag-path="release.tag_path" :tag-path="release.tagPath"
:author="release.author" :author="release.author"
:released-at="release.released_at" :released-at="release.releasedAt"
/> />
</div> </div>
</template> </template>
...@@ -31,8 +31,8 @@ export default { ...@@ -31,8 +31,8 @@ export default {
<template #user> <template #user>
<user-avatar-link <user-avatar-link
class="prepend-left-4" class="prepend-left-4"
:link-href="author.web_url" :link-href="author.webUrl"
:img-src="author.avatar_url" :img-src="author.avatarUrl"
:img-alt="userImageAltDescription" :img-alt="userImageAltDescription"
:tooltip-text="author.username" :tooltip-text="author.username"
/> />
......
...@@ -66,9 +66,9 @@ export default { ...@@ -66,9 +66,9 @@ export default {
<icon ref="commitIcon" name="commit" class="mr-1" /> <icon ref="commitIcon" name="commit" class="mr-1" />
<div v-gl-tooltip.bottom :title="commit.title"> <div v-gl-tooltip.bottom :title="commit.title">
<gl-link v-if="commitPath" :href="commitPath"> <gl-link v-if="commitPath" :href="commitPath">
{{ commit.short_id }} {{ commit.shortId }}
</gl-link> </gl-link>
<span v-else>{{ commit.short_id }}</span> <span v-else>{{ commit.shortId }}</span>
</div> </div>
</div> </div>
...@@ -100,8 +100,8 @@ export default { ...@@ -100,8 +100,8 @@ export default {
<div v-if="author" class="d-flex"> <div v-if="author" class="d-flex">
<span class="text-secondary">{{ __('by') }}&nbsp;</span> <span class="text-secondary">{{ __('by') }}&nbsp;</span>
<user-avatar-link <user-avatar-link
:link-href="author.web_url" :link-href="author.webUrl"
:img-src="author.avatar_url" :img-src="author.avatarUrl"
:img-alt="userImageAltDescription" :img-alt="userImageAltDescription"
:tooltip-text="author.username" :tooltip-text="author.username"
tooltip-placement="bottom" tooltip-placement="bottom"
......
...@@ -20,10 +20,10 @@ export default { ...@@ -20,10 +20,10 @@ export default {
}, },
computed: { computed: {
editLink() { editLink() {
return this.release._links?.edit_url; return this.release.Links?.editUrl;
}, },
selfLink() { selfLink() {
return this.release._links?.self; return this.release.Links?.self;
}, },
}, },
}; };
...@@ -36,7 +36,7 @@ export default { ...@@ -36,7 +36,7 @@ export default {
{{ release.name }} {{ release.name }}
</gl-link> </gl-link>
<template v-else>{{ release.name }}</template> <template v-else>{{ release.name }}</template>
<gl-badge v-if="release.upcoming_release" variant="warning" class="align-middle">{{ <gl-badge v-if="release.upcomingRelease" variant="warning" class="align-middle">{{
__('Upcoming Release') __('Upcoming Release')
}}</gl-badge> }}</gl-badge>
</h2> </h2>
......
...@@ -32,21 +32,21 @@ export default { ...@@ -32,21 +32,21 @@ export default {
return this.release.commit || {}; return this.release.commit || {};
}, },
commitUrl() { commitUrl() {
return this.release.commit_path; return this.release.commitPath;
}, },
hasAuthor() { hasAuthor() {
return Boolean(this.author); return Boolean(this.author);
}, },
releasedTimeAgo() { releasedTimeAgo() {
return sprintf(__('released %{time}'), { return sprintf(__('released %{time}'), {
time: this.timeFormatted(this.release.released_at), time: this.timeFormatted(this.release.releasedAt),
}); });
}, },
shouldRenderMilestones() { shouldRenderMilestones() {
return Boolean(this.release.milestones?.length); return Boolean(this.release.milestones?.length);
}, },
tagUrl() { tagUrl() {
return this.release.tag_path; return this.release.tagPath;
}, },
}, },
}; };
...@@ -57,24 +57,24 @@ export default { ...@@ -57,24 +57,24 @@ export default {
<div class="append-right-8"> <div class="append-right-8">
<icon name="commit" class="align-middle" /> <icon name="commit" class="align-middle" />
<gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl"> <gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl">
{{ commit.short_id }} {{ commit.shortId }}
</gl-link> </gl-link>
<span v-else v-gl-tooltip.bottom :title="commit.title">{{ commit.short_id }}</span> <span v-else v-gl-tooltip.bottom :title="commit.title">{{ commit.shortId }}</span>
</div> </div>
<div class="append-right-8"> <div class="append-right-8">
<icon name="tag" class="align-middle" /> <icon name="tag" class="align-middle" />
<gl-link v-if="tagUrl" v-gl-tooltip.bottom :title="__('Tag')" :href="tagUrl"> <gl-link v-if="tagUrl" v-gl-tooltip.bottom :title="__('Tag')" :href="tagUrl">
{{ release.tag_name }} {{ release.tagName }}
</gl-link> </gl-link>
<span v-else v-gl-tooltip.bottom :title="__('Tag')">{{ release.tag_name }}</span> <span v-else v-gl-tooltip.bottom :title="__('Tag')">{{ release.tagName }}</span>
</div> </div>
<release-block-milestones v-if="shouldRenderMilestones" :milestones="release.milestones" /> <release-block-milestones v-if="shouldRenderMilestones" :milestones="release.milestones" />
<div class="append-right-4"> <div class="append-right-4">
&bull; &bull;
<span v-gl-tooltip.bottom :title="tooltipTitle(release.released_at)"> <span v-gl-tooltip.bottom :title="tooltipTitle(release.releasedAt)">
{{ releasedTimeAgo }} {{ releasedTimeAgo }}
</span> </span>
</div> </div>
......
...@@ -40,7 +40,7 @@ export default { ...@@ -40,7 +40,7 @@ export default {
return Number.isNaN(percent) ? 0 : percent; return Number.isNaN(percent) ? 0 : percent;
}, },
allIssueStats() { allIssueStats() {
return this.milestones.map(m => m.issue_stats || {}); return this.milestones.map(m => m.issueStats || {});
}, },
openIssuesCount() { openIssuesCount() {
return this.allIssueStats.map(stats => stats.opened || 0).reduce(sumReducer); return this.allIssueStats.map(stats => stats.opened || 0).reduce(sumReducer);
...@@ -109,7 +109,7 @@ export default { ...@@ -109,7 +109,7 @@ export default {
:key="milestone.id" :key="milestone.id"
v-gl-tooltip v-gl-tooltip
:title="milestone.description" :title="milestone.description"
:href="milestone.web_url" :href="milestone.webUrl"
class="append-right-4" class="append-right-4"
> >
{{ milestone.title }} {{ milestone.title }}
......
...@@ -38,7 +38,7 @@ export default { ...@@ -38,7 +38,7 @@ export default {
:key="milestone.id" :key="milestone.id"
v-gl-tooltip v-gl-tooltip
:title="milestone.description" :title="milestone.description"
:href="milestone.web_url" :href="milestone.webUrl"
class="mx-1 js-milestone-link" class="mx-1 js-milestone-link"
> >
{{ milestone.title }} {{ milestone.title }}
......
...@@ -22,8 +22,7 @@ export const fetchRelease = ({ dispatch, state }) => { ...@@ -22,8 +22,7 @@ export const fetchRelease = ({ dispatch, state }) => {
return api return api
.release(state.projectId, state.tagName) .release(state.projectId, state.tagName)
.then(({ data: release }) => { .then(({ data: release }) => {
const camelCasedRelease = convertObjectPropsToCamelCase(release, { deep: true }); dispatch('receiveReleaseSuccess', convertObjectPropsToCamelCase(release, { deep: true }));
dispatch('receiveReleaseSuccess', camelCasedRelease);
}) })
.catch(error => { .catch(error => {
dispatch('receiveReleaseError', error); dispatch('receiveReleaseError', error);
......
...@@ -2,7 +2,11 @@ import * as types from './mutation_types'; ...@@ -2,7 +2,11 @@ import * as types from './mutation_types';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import api from '~/api'; import api from '~/api';
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils'; import {
normalizeHeaders,
parseIntPagination,
convertObjectPropsToCamelCase,
} from '~/lib/utils/common_utils';
/** /**
* Commits a mutation to update the state while the main endpoint is being requested. * Commits a mutation to update the state while the main endpoint is being requested.
...@@ -28,7 +32,11 @@ export const fetchReleases = ({ dispatch }, { page = '1', projectId }) => { ...@@ -28,7 +32,11 @@ export const fetchReleases = ({ dispatch }, { page = '1', projectId }) => {
export const receiveReleasesSuccess = ({ commit }, { data, headers }) => { export const receiveReleasesSuccess = ({ commit }, { data, headers }) => {
const pageInfo = parseIntPagination(normalizeHeaders(headers)); const pageInfo = parseIntPagination(normalizeHeaders(headers));
commit(types.RECEIVE_RELEASES_SUCCESS, { data, pageInfo }); const camelCasedReleases = convertObjectPropsToCamelCase(data, { deep: true });
commit(types.RECEIVE_RELEASES_SUCCESS, {
data: camelCasedReleases,
pageInfo,
});
}; };
export const receiveReleasesError = ({ commit }) => { export const receiveReleasesError = ({ commit }) => {
......
...@@ -13,7 +13,7 @@ describe('Release edit component', () => { ...@@ -13,7 +13,7 @@ describe('Release edit component', () => {
beforeEach(() => { beforeEach(() => {
gon.api_version = 'v4'; gon.api_version = 'v4';
releaseClone = JSON.parse(JSON.stringify(convertObjectPropsToCamelCase(release))); releaseClone = convertObjectPropsToCamelCase(release, { deep: true });
state = { state = {
release: releaseClone, release: releaseClone,
......
...@@ -2,12 +2,14 @@ import { mount } from '@vue/test-utils'; ...@@ -2,12 +2,14 @@ import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility'; import { truncateSha } from '~/lib/utils/text_utility';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { release } from '../mock_data'; import { release as originalRelease } from '../mock_data';
import EvidenceBlock from '~/releases/components/evidence_block.vue'; import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Evidence Block', () => { describe('Evidence Block', () => {
let wrapper; let wrapper;
let release;
const factory = (options = {}) => { const factory = (options = {}) => {
wrapper = mount(EvidenceBlock, { wrapper = mount(EvidenceBlock, {
...@@ -16,6 +18,8 @@ describe('Evidence Block', () => { ...@@ -16,6 +18,8 @@ describe('Evidence Block', () => {
}; };
beforeEach(() => { beforeEach(() => {
release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
factory({ factory({
propsData: { propsData: {
release, release,
...@@ -32,7 +36,7 @@ describe('Evidence Block', () => { ...@@ -32,7 +36,7 @@ describe('Evidence Block', () => {
}); });
it('renders the title for the dowload link', () => { it('renders the title for the dowload link', () => {
expect(wrapper.find(GlLink).text()).toBe(`${release.tag_name}-evidence.json`); expect(wrapper.find(GlLink).text()).toBe(`${release.tagName}-evidence.json`);
}); });
it('renders the correct hover text for the download', () => { it('renders the correct hover text for the download', () => {
...@@ -40,19 +44,19 @@ describe('Evidence Block', () => { ...@@ -40,19 +44,19 @@ describe('Evidence Block', () => {
}); });
it('renders the correct file link for download', () => { it('renders the correct file link for download', () => {
expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tag_name}-evidence.json`); expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tagName}-evidence.json`);
}); });
describe('sha text', () => { describe('sha text', () => {
it('renders the short sha initially', () => { it('renders the short sha initially', () => {
expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidence_sha)); expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidenceSha));
}); });
it('renders the long sha after expansion', () => { it('renders the long sha after expansion', () => {
wrapper.find('.js-text-expander-prepend').trigger('click'); wrapper.find('.js-text-expander-prepend').trigger('click');
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find('.js-expanded').text()).toBe(release.evidence_sha); expect(wrapper.find('.js-expanded').text()).toBe(release.evidenceSha);
}); });
}); });
}); });
...@@ -68,7 +72,7 @@ describe('Evidence Block', () => { ...@@ -68,7 +72,7 @@ describe('Evidence Block', () => {
it('copies the sha', () => { it('copies the sha', () => {
expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe( expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe(
release.evidence_sha, release.evidenceSha,
); );
}); });
}); });
......
...@@ -24,7 +24,7 @@ describe('Release block footer', () => { ...@@ -24,7 +24,7 @@ describe('Release block footer', () => {
const factory = (props = {}) => { const factory = (props = {}) => {
wrapper = mount(ReleaseBlockFooter, { wrapper = mount(ReleaseBlockFooter, {
propsData: { propsData: {
...convertObjectPropsToCamelCase(releaseClone), ...convertObjectPropsToCamelCase(releaseClone, { deep: true }),
...props, ...props,
}, },
}); });
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { cloneDeep, merge } from 'lodash'; import { merge } from 'lodash';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import ReleaseBlockHeader from '~/releases/components/release_block_header.vue'; import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
...@@ -18,9 +18,7 @@ describe('Release block header', () => { ...@@ -18,9 +18,7 @@ describe('Release block header', () => {
}; };
beforeEach(() => { beforeEach(() => {
release = convertObjectPropsToCamelCase(cloneDeep(originalRelease), { release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
ignoreKeyNames: ['_links'],
});
}); });
afterEach(() => { afterEach(() => {
...@@ -39,13 +37,13 @@ describe('Release block header', () => { ...@@ -39,13 +37,13 @@ describe('Release block header', () => {
const link = findHeaderLink(); const link = findHeaderLink();
expect(link.text()).toBe(release.name); expect(link.text()).toBe(release.name);
expect(link.attributes('href')).toBe(release._links.self); expect(link.attributes('href')).toBe(release.Links.self);
}); });
}); });
describe('when _links.self is missing', () => { describe('when _links.self is missing', () => {
beforeEach(() => { beforeEach(() => {
factory({ _links: { self: null } }); factory({ Links: { self: null } });
}); });
it('renders the title as text', () => { it('renders the title as text', () => {
......
...@@ -2,12 +2,13 @@ import { mount } from '@vue/test-utils'; ...@@ -2,12 +2,13 @@ import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui'; import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue'; import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue';
import { milestones } from '../mock_data'; import { milestones as originalMilestones } from '../mock_data';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants'; import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Release block milestone info', () => { describe('Release block milestone info', () => {
let wrapper; let wrapper;
let milestonesClone; let milestones;
const factory = milestonesProp => { const factory = milestonesProp => {
wrapper = mount(ReleaseBlockMilestoneInfo, { wrapper = mount(ReleaseBlockMilestoneInfo, {
...@@ -20,7 +21,7 @@ describe('Release block milestone info', () => { ...@@ -20,7 +21,7 @@ describe('Release block milestone info', () => {
}; };
beforeEach(() => { beforeEach(() => {
milestonesClone = JSON.parse(JSON.stringify(milestones)); milestones = convertObjectPropsToCamelCase(originalMilestones, { deep: true });
}); });
afterEach(() => { afterEach(() => {
...@@ -32,7 +33,7 @@ describe('Release block milestone info', () => { ...@@ -32,7 +33,7 @@ describe('Release block milestone info', () => {
const issuesContainer = () => wrapper.find('.js-issues-container'); const issuesContainer = () => wrapper.find('.js-issues-container');
describe('with default props', () => { describe('with default props', () => {
beforeEach(() => factory(milestonesClone)); beforeEach(() => factory(milestones));
it('renders the correct percentage', () => { it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete'); expect(milestoneProgressBarContainer().text()).toContain('41% complete');
...@@ -53,13 +54,13 @@ describe('Release block milestone info', () => { ...@@ -53,13 +54,13 @@ describe('Release block milestone info', () => {
it('renders a list of links to all associated milestones', () => { it('renders a list of links to all associated milestones', () => {
expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5'); expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
milestonesClone.forEach((m, i) => { milestones.forEach((m, i) => {
const milestoneLink = milestoneListContainer() const milestoneLink = milestoneListContainer()
.findAll(GlLink) .findAll(GlLink)
.at(i); .at(i);
expect(milestoneLink.text()).toBe(m.title); expect(milestoneLink.text()).toBe(m.title);
expect(milestoneLink.attributes('href')).toBe(m.web_url); expect(milestoneLink.attributes('href')).toBe(m.webUrl);
expect(milestoneLink.attributes('title')).toBe(m.description); expect(milestoneLink.attributes('title')).toBe(m.description);
}); });
}); });
...@@ -84,7 +85,7 @@ describe('Release block milestone info', () => { ...@@ -84,7 +85,7 @@ describe('Release block milestone info', () => {
beforeEach(() => { beforeEach(() => {
lotsOfMilestones = []; lotsOfMilestones = [];
const template = milestonesClone[0]; const template = milestones[0];
for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) { for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) {
lotsOfMilestones.push({ lotsOfMilestones.push({
...@@ -148,16 +149,16 @@ describe('Release block milestone info', () => { ...@@ -148,16 +149,16 @@ describe('Release block milestone info', () => {
/** Ensures we don't have any issues with dividing by zero when computing percentages */ /** Ensures we don't have any issues with dividing by zero when computing percentages */
describe('when all issue counts are zero', () => { describe('when all issue counts are zero', () => {
beforeEach(() => { beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({ milestones = milestones.map(m => ({
...m, ...m,
issue_stats: { issueStats: {
...m.issue_stats, ...m.issueStats,
opened: 0, opened: 0,
closed: 0, closed: 0,
}, },
})); }));
return factory(milestonesClone); return factory(milestones);
}); });
expectAllZeros(); expectAllZeros();
...@@ -165,12 +166,12 @@ describe('Release block milestone info', () => { ...@@ -165,12 +166,12 @@ describe('Release block milestone info', () => {
describe('if the API response is missing the "issue_stats" property', () => { describe('if the API response is missing the "issue_stats" property', () => {
beforeEach(() => { beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({ milestones = milestones.map(m => ({
...m, ...m,
issue_stats: undefined, issueStats: undefined,
})); }));
return factory(milestonesClone); return factory(milestones);
}); });
expectAllZeros(); expectAllZeros();
......
...@@ -5,10 +5,12 @@ import EvidenceBlock from '~/releases/components/evidence_block.vue'; ...@@ -5,10 +5,12 @@ import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ReleaseBlock from '~/releases/components/release_block.vue'; import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue'; import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago'; import timeagoMixin from '~/vue_shared/mixins/timeago';
import { release } from '../mock_data'; import { release as originalRelease } from '../mock_data';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement } from '~/lib/utils/common_utils';
const { convertObjectPropsToCamelCase } = jest.requireActual('~/lib/utils/common_utils');
let mockLocationHash; let mockLocationHash;
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
__esModule: true, __esModule: true,
...@@ -22,7 +24,7 @@ jest.mock('~/lib/utils/common_utils', () => ({ ...@@ -22,7 +24,7 @@ jest.mock('~/lib/utils/common_utils', () => ({
describe('Release block', () => { describe('Release block', () => {
let wrapper; let wrapper;
let releaseClone; let release;
const factory = (releaseProp, featureFlags = {}) => { const factory = (releaseProp, featureFlags = {}) => {
wrapper = mount(ReleaseBlock, { wrapper = mount(ReleaseBlock, {
...@@ -45,7 +47,7 @@ describe('Release block', () => { ...@@ -45,7 +47,7 @@ describe('Release block', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn($.fn, 'renderGFM'); jest.spyOn($.fn, 'renderGFM');
releaseClone = JSON.parse(JSON.stringify(release)); release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
}); });
afterEach(() => { afterEach(() => {
...@@ -61,7 +63,7 @@ describe('Release block', () => { ...@@ -61,7 +63,7 @@ describe('Release block', () => {
it('renders an edit button that links to the "Edit release" page', () => { it('renders an edit button that links to the "Edit release" page', () => {
expect(editButton().exists()).toBe(true); expect(editButton().exists()).toBe(true);
expect(editButton().attributes('href')).toBe(release._links.edit_url); expect(editButton().attributes('href')).toBe(release.Links.editUrl);
}); });
it('renders release name', () => { it('renders release name', () => {
...@@ -74,7 +76,7 @@ describe('Release block', () => { ...@@ -74,7 +76,7 @@ describe('Release block', () => {
}); });
it('renders release date', () => { it('renders release date', () => {
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at)); expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.releasedAt));
}); });
it('renders number of assets provided', () => { it('renders number of assets provided', () => {
...@@ -129,72 +131,72 @@ describe('Release block', () => { ...@@ -129,72 +131,72 @@ describe('Release block', () => {
}); });
it('renders commit sha', () => { it('renders commit sha', () => {
releaseClone.commit_path = '/commit/example'; release.commitPath = '/commit/example';
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(wrapper.text()).toContain(release.commit.short_id); expect(wrapper.text()).toContain(release.commit.shortId);
expect(wrapper.find('a[href="/commit/example"]').exists()).toBe(true); expect(wrapper.find('a[href="/commit/example"]').exists()).toBe(true);
}); });
}); });
it('renders tag name', () => { it('renders tag name', () => {
releaseClone.tag_path = '/tag/example'; release.tagPath = '/tag/example';
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(wrapper.text()).toContain(release.tag_name); expect(wrapper.text()).toContain(release.tagName);
expect(wrapper.find('a[href="/tag/example"]').exists()).toBe(true); expect(wrapper.find('a[href="/tag/example"]').exists()).toBe(true);
}); });
}); });
it("does not render an edit button if release._links.edit_url isn't a string", () => { it("does not render an edit button if release.Links.editUrl isn't a string", () => {
delete releaseClone._links; delete release.Links;
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(editButton().exists()).toBe(false); expect(editButton().exists()).toBe(false);
}); });
}); });
it('does not render the milestone list if no milestones are associated to the release', () => { it('does not render the milestone list if no milestones are associated to the release', () => {
delete releaseClone.milestones; delete release.milestones;
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(milestoneListLabel().exists()).toBe(false); expect(milestoneListLabel().exists()).toBe(false);
}); });
}); });
it('renders upcoming release badge', () => { it('renders upcoming release badge', () => {
releaseClone.upcoming_release = true; release.upcomingRelease = true;
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(wrapper.text()).toContain('Upcoming Release'); expect(wrapper.text()).toContain('Upcoming Release');
}); });
}); });
it('slugifies the tag_name before setting it as the elements ID', () => { it('slugifies the tagName before setting it as the elements ID', () => {
releaseClone.tag_name = 'a dangerous tag name <script>alert("hello")</script>'; release.tagName = 'a dangerous tag name <script>alert("hello")</script>';
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script'); expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script');
}); });
}); });
describe('evidence block', () => { describe('evidence block', () => {
it('renders the evidence block when the evidence is available and the feature flag is true', () => it('renders the evidence block when the evidence is available and the feature flag is true', () =>
factory(releaseClone, { releaseEvidenceCollection: true }).then(() => factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true), 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', () => it('does not render the evidence block when the evidence is available but the feature flag is false', () =>
factory(releaseClone, { releaseEvidenceCollection: true }).then(() => factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true), expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
)); ));
it('does not render the evidence block when there is no evidence', () => { it('does not render the evidence block when there is no evidence', () => {
releaseClone.evidence_sha = null; release.evidenceSha = null;
return factory(releaseClone).then(() => { return factory(release).then(() => {
expect(wrapper.find(EvidenceBlock).exists()).toBe(false); expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
}); });
}); });
...@@ -222,7 +224,7 @@ describe('Release block', () => { ...@@ -222,7 +224,7 @@ describe('Release block', () => {
}); });
it("attempts to scroll itself into view if the anchor tag matches the release's tag name", () => { it("attempts to scroll itself into view if the anchor tag matches the release's tag name", () => {
mockLocationHash = release.tag_name; mockLocationHash = release.tagName;
return factory(release).then(() => { return factory(release).then(() => {
expect(scrollToElement).toHaveBeenCalledTimes(1); expect(scrollToElement).toHaveBeenCalledTimes(1);
...@@ -231,7 +233,7 @@ describe('Release block', () => { ...@@ -231,7 +233,7 @@ describe('Release block', () => {
}); });
it('renders with a light blue background if it is the target of the anchor', () => { it('renders with a light blue background if it is the target of the anchor', () => {
mockLocationHash = release.tag_name; mockLocationHash = release.tagName;
return factory(release).then(() => { return factory(release).then(() => {
expect(hasTargetBlueBackground()).toBe(true); expect(hasTargetBlueBackground()).toBe(true);
...@@ -275,16 +277,16 @@ describe('Release block', () => { ...@@ -275,16 +277,16 @@ describe('Release block', () => {
expect(milestoneLink.text()).toBe(milestone.title); expect(milestoneLink.text()).toBe(milestone.title);
expect(milestoneLink.attributes('href')).toBe(milestone.web_url); expect(milestoneLink.attributes('href')).toBe(milestone.webUrl);
expect(milestoneLink.attributes('title')).toBe(milestone.description); expect(milestoneLink.attributes('title')).toBe(milestone.description);
}); });
}); });
it('renders the label as "Milestone" if only a single milestone is passed in', () => { it('renders the label as "Milestone" if only a single milestone is passed in', () => {
releaseClone.milestones = releaseClone.milestones.slice(0, 1); release.milestones = release.milestones.slice(0, 1);
return factory(releaseClone, { releaseIssueSummary: false }).then(() => { return factory(release, { releaseIssueSummary: false }).then(() => {
expect( expect(
milestoneListLabel() milestoneListLabel()
.find('.js-label-text') .find('.js-label-text')
......
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
release, release,
releases, releases,
} from '../mock_data'; } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Releases App ', () => { describe('Releases App ', () => {
const Component = Vue.extend(app); const Component = Vue.extend(app);
...@@ -27,7 +28,10 @@ describe('Releases App ', () => { ...@@ -27,7 +28,10 @@ describe('Releases App ', () => {
beforeEach(() => { beforeEach(() => {
store = createStore({ list: listModule }); store = createStore({ list: listModule });
releasesPagination = _.range(21).map(index => ({ ...release, tag_name: `${index}.00` })); releasesPagination = _.range(21).map(index => ({
...convertObjectPropsToCamelCase(release, { deep: true }),
tagName: `${index}.00`,
}));
}); });
afterEach(() => { afterEach(() => {
......
...@@ -8,16 +8,18 @@ import { ...@@ -8,16 +8,18 @@ import {
import state from '~/releases/stores/modules/list/state'; import state from '~/releases/stores/modules/list/state';
import * as types from '~/releases/stores/modules/list/mutation_types'; import * as types from '~/releases/stores/modules/list/mutation_types';
import api from '~/api'; import api from '~/api';
import { parseIntPagination } from '~/lib/utils/common_utils'; import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data'; import { pageInfoHeadersWithoutPagination, releases as originalReleases } from '../../../mock_data';
describe('Releases State actions', () => { describe('Releases State actions', () => {
let mockedState; let mockedState;
let pageInfo; let pageInfo;
let releases;
beforeEach(() => { beforeEach(() => {
mockedState = state(); mockedState = state();
pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination); pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
}); });
describe('requestReleases', () => { describe('requestReleases', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment