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-03-04 12:08:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-04 12:08:20 +0300
commitd80f3cd75e700b6e62910865bfd36734644ffa89 (patch)
treeaa2fa2f2b4385854c13591bef8e74924ef661657 /spec/frontend/releases/components
parentbe81c1578d65f25edfde8aa550f190b8d3e6d976 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/releases/components')
-rw-r--r--spec/frontend/releases/components/app_edit_spec.js136
-rw-r--r--spec/frontend/releases/components/app_show_spec.js61
-rw-r--r--spec/frontend/releases/components/release_block_header_spec.js37
-rw-r--r--spec/frontend/releases/components/release_block_spec.js56
4 files changed, 206 insertions, 84 deletions
diff --git a/spec/frontend/releases/components/app_edit_spec.js b/spec/frontend/releases/components/app_edit_spec.js
index b2dbb8cc435..ac4b2b9124f 100644
--- a/spec/frontend/releases/components/app_edit_spec.js
+++ b/spec/frontend/releases/components/app_edit_spec.js
@@ -1,30 +1,27 @@
import Vuex from 'vuex';
import { mount } from '@vue/test-utils';
import ReleaseEditApp from '~/releases/components/app_edit.vue';
-import { release } from '../mock_data';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { release as originalRelease } from '../mock_data';
+import * as commonUtils from '~/lib/utils/common_utils';
+import { BACK_URL_PARAM } from '~/releases/constants';
describe('Release edit component', () => {
let wrapper;
- let releaseClone;
+ let release;
let actions;
let state;
- beforeEach(() => {
- gon.api_version = 'v4';
-
- releaseClone = convertObjectPropsToCamelCase(release, { deep: true });
-
+ const factory = () => {
state = {
- release: releaseClone,
+ release,
markdownDocsPath: 'path/to/markdown/docs',
updateReleaseApiDocsPath: 'path/to/update/release/api/docs',
+ releasesPagePath: 'path/to/releases/page',
};
actions = {
fetchRelease: jest.fn(),
updateRelease: jest.fn(),
- navigateToReleasesPage: jest.fn(),
};
const store = new Vuex.Store({
@@ -40,58 +37,99 @@ describe('Release edit component', () => {
wrapper = mount(ReleaseEditApp, {
store,
});
+ };
- return wrapper.vm.$nextTick();
- });
+ beforeEach(() => {
+ gon.api_version = 'v4';
- it('calls fetchRelease when the component is created', () => {
- expect(actions.fetchRelease).toHaveBeenCalledTimes(1);
+ release = commonUtils.convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
- it('renders the description text at the top of the page', () => {
- expect(wrapper.find('.js-subtitle-text').text()).toBe(
- 'Releases are based on Git tags. We recommend naming tags that fit within semantic versioning, for example v1.0, v2.0-pre.',
- );
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
});
- it('renders the correct tag name in the "Tag name" field', () => {
- expect(wrapper.find('#git-ref').element.value).toBe(releaseClone.tagName);
- });
+ describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
+ beforeEach(() => {
+ factory();
+ });
- it('renders the correct help text under the "Tag name" field', () => {
- const helperText = wrapper.find('#tag-name-help');
- const helperTextLink = helperText.find('a');
- const helperTextLinkAttrs = helperTextLink.attributes();
-
- expect(helperText.text()).toBe(
- 'Changing a Release tag is only supported via Releases API. More information',
- );
- expect(helperTextLink.text()).toBe('More information');
- expect(helperTextLinkAttrs.href).toBe(state.updateReleaseApiDocsPath);
- expect(helperTextLinkAttrs.rel).toContain('noopener');
- expect(helperTextLinkAttrs.rel).toContain('noreferrer');
- expect(helperTextLinkAttrs.target).toBe('_blank');
- });
+ it('calls fetchRelease when the component is created', () => {
+ expect(actions.fetchRelease).toHaveBeenCalledTimes(1);
+ });
- it('renders the correct release title in the "Release title" field', () => {
- expect(wrapper.find('#release-title').element.value).toBe(releaseClone.name);
- });
+ it('renders the description text at the top of the page', () => {
+ expect(wrapper.find('.js-subtitle-text').text()).toBe(
+ 'Releases are based on Git tags. We recommend naming tags that fit within semantic versioning, for example v1.0, v2.0-pre.',
+ );
+ });
- it('renders the release notes in the "Release notes" textarea', () => {
- expect(wrapper.find('#release-notes').element.value).toBe(releaseClone.description);
- });
+ it('renders the correct tag name in the "Tag name" field', () => {
+ expect(wrapper.find('#git-ref').element.value).toBe(release.tagName);
+ });
+
+ it('renders the correct help text under the "Tag name" field', () => {
+ const helperText = wrapper.find('#tag-name-help');
+ const helperTextLink = helperText.find('a');
+ const helperTextLinkAttrs = helperTextLink.attributes();
+
+ expect(helperText.text()).toBe(
+ 'Changing a Release tag is only supported via Releases API. More information',
+ );
+ expect(helperTextLink.text()).toBe('More information');
+ expect(helperTextLinkAttrs).toEqual(
+ expect.objectContaining({
+ href: state.updateReleaseApiDocsPath,
+ rel: 'noopener noreferrer',
+ target: '_blank',
+ }),
+ );
+ });
+
+ it('renders the correct release title in the "Release title" field', () => {
+ expect(wrapper.find('#release-title').element.value).toBe(release.name);
+ });
+
+ it('renders the release notes in the "Release notes" textarea', () => {
+ expect(wrapper.find('#release-notes').element.value).toBe(release.description);
+ });
+
+ it('renders the "Save changes" button as type="submit"', () => {
+ expect(wrapper.find('.js-submit-button').attributes('type')).toBe('submit');
+ });
- it('renders the "Save changes" button as type="submit"', () => {
- expect(wrapper.find('.js-submit-button').attributes('type')).toBe('submit');
+ it('calls updateRelease when the form is submitted', () => {
+ wrapper.find('form').trigger('submit');
+ expect(actions.updateRelease).toHaveBeenCalledTimes(1);
+ });
});
- it('calls updateRelease when the form is submitted', () => {
- wrapper.find('form').trigger('submit');
- expect(actions.updateRelease).toHaveBeenCalledTimes(1);
+ describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
+ beforeEach(() => {
+ factory();
+ });
+
+ it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
+ const cancelButton = wrapper.find('.js-cancel-button');
+ expect(cancelButton.attributes().href).toBe(state.releasesPagePath);
+ });
});
- it('calls navigateToReleasesPage when the "Cancel" button is clicked', () => {
- wrapper.find('.js-cancel-button').vm.$emit('click');
- expect(actions.navigateToReleasesPage).toHaveBeenCalledTimes(1);
+ describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => {
+ const backUrl = 'https://example.gitlab.com/back/url';
+
+ beforeEach(() => {
+ commonUtils.getParameterByName = jest
+ .fn()
+ .mockImplementation(paramToGet => ({ [BACK_URL_PARAM]: backUrl }[paramToGet]));
+
+ factory();
+ });
+
+ it('renders a "Cancel" button with an href pointing to the main Releases page', () => {
+ const cancelButton = wrapper.find('.js-cancel-button');
+ expect(cancelButton.attributes().href).toBe(backUrl);
+ });
});
});
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
new file mode 100644
index 00000000000..3dc9964c25c
--- /dev/null
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -0,0 +1,61 @@
+import Vuex from 'vuex';
+import { shallowMount } from '@vue/test-utils';
+import ReleaseShowApp from '~/releases/components/app_show.vue';
+import { release as originalRelease } from '../mock_data';
+import { GlSkeletonLoading } from '@gitlab/ui';
+import ReleaseBlock from '~/releases/components/release_block.vue';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+describe('Release show component', () => {
+ let wrapper;
+ let release;
+ let actions;
+
+ beforeEach(() => {
+ release = convertObjectPropsToCamelCase(originalRelease);
+ });
+
+ const factory = state => {
+ actions = {
+ fetchRelease: jest.fn(),
+ };
+
+ const store = new Vuex.Store({
+ modules: {
+ detail: {
+ namespaced: true,
+ actions,
+ state,
+ },
+ },
+ });
+
+ wrapper = shallowMount(ReleaseShowApp, { store });
+ };
+
+ const findLoadingSkeleton = () => wrapper.find(GlSkeletonLoading);
+ const findReleaseBlock = () => wrapper.find(ReleaseBlock);
+
+ it('calls fetchRelease when the component is created', () => {
+ factory({ release });
+ expect(actions.fetchRelease).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows a loading skeleton and hides the release block while the API call is in progress', () => {
+ factory({ isFetchingRelease: true });
+ expect(findLoadingSkeleton().exists()).toBe(true);
+ expect(findReleaseBlock().exists()).toBe(false);
+ });
+
+ it('hides the loading skeleton and shows the release block when the API call finishes successfully', () => {
+ factory({ isFetchingRelease: false });
+ expect(findLoadingSkeleton().exists()).toBe(false);
+ expect(findReleaseBlock().exists()).toBe(true);
+ });
+
+ it('hides both the loading skeleton and the release block when the API call fails', () => {
+ factory({ fetchError: new Error('Uh oh') });
+ expect(findLoadingSkeleton().exists()).toBe(false);
+ expect(findReleaseBlock().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/releases/components/release_block_header_spec.js b/spec/frontend/releases/components/release_block_header_spec.js
index 44f6f63fa79..9c6cbc86d3c 100644
--- a/spec/frontend/releases/components/release_block_header_spec.js
+++ b/spec/frontend/releases/components/release_block_header_spec.js
@@ -4,6 +4,7 @@ import { GlLink } from '@gitlab/ui';
import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { release as originalRelease } from '../mock_data';
+import { BACK_URL_PARAM } from '~/releases/constants';
describe('Release block header', () => {
let wrapper;
@@ -27,6 +28,7 @@ describe('Release block header', () => {
const findHeader = () => wrapper.find('h2');
const findHeaderLink = () => findHeader().find(GlLink);
+ const findEditButton = () => wrapper.find('.js-edit-button');
describe('when _links.self is provided', () => {
beforeEach(() => {
@@ -51,4 +53,39 @@ describe('Release block header', () => {
expect(findHeaderLink().exists()).toBe(false);
});
});
+
+ describe('when _links.edit_url is provided', () => {
+ const currentUrl = 'https://example.gitlab.com/path';
+
+ beforeEach(() => {
+ Object.defineProperty(window, 'location', {
+ writable: true,
+ value: {
+ href: currentUrl,
+ },
+ });
+
+ factory();
+ });
+
+ it('renders an edit button', () => {
+ expect(findEditButton().exists()).toBe(true);
+ });
+
+ it('renders the edit button with the correct href', () => {
+ const expectedQueryParam = `${BACK_URL_PARAM}=${encodeURIComponent(currentUrl)}`;
+ const expectedUrl = `${release._links.editUrl}?${expectedQueryParam}`;
+ expect(findEditButton().attributes().href).toBe(expectedUrl);
+ });
+ });
+
+ describe('when _links.edit is missing', () => {
+ beforeEach(() => {
+ factory({ _links: { editUrl: null } });
+ });
+
+ it('does not render an edit button', () => {
+ expect(findEditButton().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js
index ff88e3193bc..227998b0271 100644
--- a/spec/frontend/releases/components/release_block_spec.js
+++ b/spec/frontend/releases/components/release_block_spec.js
@@ -7,20 +7,9 @@ import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { release as originalRelease } from '../mock_data';
import Icon from '~/vue_shared/components/icon.vue';
-import { scrollToElement } from '~/lib/utils/common_utils';
-
-const { convertObjectPropsToCamelCase } = jest.requireActual('~/lib/utils/common_utils');
-
-let mockLocationHash;
-jest.mock('~/lib/utils/url_utility', () => ({
- __esModule: true,
- getLocationHash: jest.fn().mockImplementation(() => mockLocationHash),
-}));
-
-jest.mock('~/lib/utils/common_utils', () => ({
- __esModule: true,
- scrollToElement: jest.fn(),
-}));
+import * as commonUtils from '~/lib/utils/common_utils';
+import { BACK_URL_PARAM } from '~/releases/constants';
+import * as urlUtility from '~/lib/utils/url_utility';
describe('Release block', () => {
let wrapper;
@@ -47,7 +36,7 @@ describe('Release block', () => {
beforeEach(() => {
jest.spyOn($.fn, 'renderGFM');
- release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
+ release = commonUtils.convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
afterEach(() => {
@@ -61,9 +50,11 @@ describe('Release block', () => {
expect(wrapper.attributes().id).toBe('v0.3');
});
- it('renders an edit button that links to the "Edit release" page', () => {
+ it(`renders an edit button that links to the "Edit release" page with a "${BACK_URL_PARAM}" parameter`, () => {
expect(editButton().exists()).toBe(true);
- expect(editButton().attributes('href')).toBe(release._links.editUrl);
+ expect(editButton().attributes('href')).toBe(
+ `${release._links.editUrl}?${BACK_URL_PARAM}=${encodeURIComponent(window.location.href)}`,
+ );
});
it('renders release name', () => {
@@ -150,14 +141,6 @@ describe('Release block', () => {
});
});
- it("does not render an edit button if release._links.editUrl isn't a string", () => {
- delete release._links;
-
- return factory(release).then(() => {
- expect(editButton().exists()).toBe(false);
- });
- });
-
it('does not render the milestone list if no milestones are associated to the release', () => {
delete release.milestones;
@@ -203,37 +186,40 @@ describe('Release block', () => {
});
describe('anchor scrolling', () => {
+ let locationHash;
+
beforeEach(() => {
- scrollToElement.mockClear();
+ commonUtils.scrollToElement = jest.fn();
+ urlUtility.getLocationHash = jest.fn().mockImplementation(() => locationHash);
});
const hasTargetBlueBackground = () => wrapper.classes('bg-line-target-blue');
it('does not attempt to scroll the page if no anchor tag is included in the URL', () => {
- mockLocationHash = '';
+ locationHash = '';
return factory(release).then(() => {
- expect(scrollToElement).not.toHaveBeenCalled();
+ expect(commonUtils.scrollToElement).not.toHaveBeenCalled();
});
});
it("does not attempt to scroll the page if the anchor tag doesn't match the release's tag name", () => {
- mockLocationHash = 'v0.4';
+ locationHash = 'v0.4';
return factory(release).then(() => {
- expect(scrollToElement).not.toHaveBeenCalled();
+ expect(commonUtils.scrollToElement).not.toHaveBeenCalled();
});
});
it("attempts to scroll itself into view if the anchor tag matches the release's tag name", () => {
- mockLocationHash = release.tagName;
+ locationHash = release.tagName;
return factory(release).then(() => {
- expect(scrollToElement).toHaveBeenCalledTimes(1);
+ expect(commonUtils.scrollToElement).toHaveBeenCalledTimes(1);
- expect(scrollToElement).toHaveBeenCalledWith(wrapper.element);
+ expect(commonUtils.scrollToElement).toHaveBeenCalledWith(wrapper.element);
});
});
it('renders with a light blue background if it is the target of the anchor', () => {
- mockLocationHash = release.tagName;
+ locationHash = release.tagName;
return factory(release).then(() => {
expect(hasTargetBlueBackground()).toBe(true);
@@ -241,7 +227,7 @@ describe('Release block', () => {
});
it('does not render with a light blue background if it is not the target of the anchor', () => {
- mockLocationHash = '';
+ locationHash = '';
return factory(release).then(() => {
expect(hasTargetBlueBackground()).toBe(false);