summaryrefslogtreecommitdiff
path: root/spec/frontend/environments
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/environments')
-rw-r--r--spec/frontend/environments/delete_environment_modal_spec.js6
-rw-r--r--spec/frontend/environments/edit_environment_spec.js4
-rw-r--r--spec/frontend/environments/empty_state_spec.js52
-rw-r--r--spec/frontend/environments/enable_review_app_modal_spec.js23
-rw-r--r--spec/frontend/environments/environment_external_url_spec.js31
-rw-r--r--spec/frontend/environments/environment_folder_spec.js22
-rw-r--r--spec/frontend/environments/environments_app_spec.js53
-rw-r--r--spec/frontend/environments/environments_detail_header_spec.js21
-rw-r--r--spec/frontend/environments/graphql/resolvers_spec.js26
-rw-r--r--spec/frontend/environments/new_environment_spec.js4
10 files changed, 201 insertions, 41 deletions
diff --git a/spec/frontend/environments/delete_environment_modal_spec.js b/spec/frontend/environments/delete_environment_modal_spec.js
index 48e4f661c1d..cc18bf754eb 100644
--- a/spec/frontend/environments/delete_environment_modal_spec.js
+++ b/spec/frontend/environments/delete_environment_modal_spec.js
@@ -6,7 +6,7 @@ import { s__, sprintf } from '~/locale';
import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { resolvedEnvironment } from './graphql/mock_data';
jest.mock('~/flash');
@@ -57,7 +57,7 @@ describe('~/environments/components/delete_environment_modal.vue', () => {
await nextTick();
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
expect(deleteResolver).toHaveBeenCalledWith(
expect.anything(),
@@ -76,7 +76,7 @@ describe('~/environments/components/delete_environment_modal.vue', () => {
await waitForPromises();
- expect(createFlash).toHaveBeenCalledWith(
+ expect(createAlert).toHaveBeenCalledWith(
expect.objectContaining({
message: s__(
'Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.',
diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js
index 0f2d6e95bf0..5ea23af4c16 100644
--- a/spec/frontend/environments/edit_environment_spec.js
+++ b/spec/frontend/environments/edit_environment_spec.js
@@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import EditEnvironment from '~/environments/components/edit_environment.vue';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
@@ -85,7 +85,7 @@ describe('~/environments/components/edit.vue', () => {
await submitForm(expected, [400, { message: ['uh oh!'] }]);
- expect(createFlash).toHaveBeenCalledWith({ message: 'uh oh!' });
+ expect(createAlert).toHaveBeenCalledWith({ message: 'uh oh!' });
expect(showsLoading()).toBe(false);
});
diff --git a/spec/frontend/environments/empty_state_spec.js b/spec/frontend/environments/empty_state_spec.js
index 974afc6d032..02cf2dc3c68 100644
--- a/spec/frontend/environments/empty_state_spec.js
+++ b/spec/frontend/environments/empty_state_spec.js
@@ -4,10 +4,21 @@ import EmptyState from '~/environments/components/empty_state.vue';
import { ENVIRONMENTS_SCOPE } from '~/environments/constants';
const HELP_PATH = '/help';
+const NEW_PATH = '/new';
describe('~/environments/components/empty_state.vue', () => {
let wrapper;
+ const findNewEnvironmentLink = () =>
+ wrapper.findByRole('link', {
+ name: s__('Environments|New environment'),
+ });
+
+ const findDocsLink = () =>
+ wrapper.findByRole('link', {
+ name: s__('Environments|How do I create an environment?'),
+ });
+
const createWrapper = ({ propsData = {} } = {}) =>
mountExtended(EmptyState, {
propsData: {
@@ -15,6 +26,7 @@ describe('~/environments/components/empty_state.vue', () => {
helpPath: HELP_PATH,
...propsData,
},
+ provide: { newEnvironmentPath: NEW_PATH },
});
afterEach(() => {
@@ -44,10 +56,44 @@ describe('~/environments/components/empty_state.vue', () => {
it('shows a link to the the help path', () => {
wrapper = createWrapper();
- const link = wrapper.findByRole('link', {
- name: s__('Environments|How do I create an environment?'),
- });
+ const link = findDocsLink();
expect(link.attributes('href')).toBe(HELP_PATH);
});
+
+ it('hides a link to creating a new environment', () => {
+ const link = findNewEnvironmentLink();
+
+ expect(link.exists()).toBe(false);
+ });
+
+ describe('with search term', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({ propsData: { hasTerm: true } });
+ });
+
+ it('should show text about searching', () => {
+ const header = wrapper.findByRole('heading', {
+ name: s__('Environments|No results found'),
+ });
+
+ expect(header.exists()).toBe(true);
+
+ const text = wrapper.findByText(s__('Environments|Edit your search and try again'));
+
+ expect(text.exists()).toBe(true);
+ });
+
+ it('hides the documentation link', () => {
+ const link = findDocsLink();
+
+ expect(link.exists()).toBe(false);
+ });
+
+ it('shows a link to create a new environment', () => {
+ const link = findNewEnvironmentLink();
+
+ expect(link.attributes('href')).toBe(NEW_PATH);
+ });
+ });
});
diff --git a/spec/frontend/environments/enable_review_app_modal_spec.js b/spec/frontend/environments/enable_review_app_modal_spec.js
index b6dac811ea6..7939bd600dc 100644
--- a/spec/frontend/environments/enable_review_app_modal_spec.js
+++ b/spec/frontend/environments/enable_review_app_modal_spec.js
@@ -1,7 +1,8 @@
import { shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import EnableReviewAppButton from '~/environments/components/enable_review_app_modal.vue';
+import EnableReviewAppModal from '~/environments/components/enable_review_app_modal.vue';
+import { REVIEW_APP_MODAL_I18N as i18n } from '~/environments/constants';
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
// hardcode uniqueId for determinism
@@ -9,10 +10,12 @@ jest.mock('lodash/uniqueId', () => (x) => `${x}77`);
const EXPECTED_COPY_PRE_ID = 'enable-review-app-copy-string-77';
-describe('Enable Review App Button', () => {
+describe('Enable Review App Modal', () => {
let wrapper;
let modal;
+ const findInstructions = () => wrapper.findAll('ol li');
+ const findInstructionAt = (i) => wrapper.findAll('ol li').at(i);
const findCopyString = () => wrapper.find(`#${EXPECTED_COPY_PRE_ID}`);
afterEach(() => {
@@ -22,29 +25,31 @@ describe('Enable Review App Button', () => {
describe('renders the modal', () => {
beforeEach(() => {
wrapper = extendedWrapper(
- shallowMount(EnableReviewAppButton, {
+ shallowMount(EnableReviewAppModal, {
propsData: {
modalId: 'fake-id',
visible: true,
},
- provide: {
- defaultBranchName: 'main',
- },
}),
);
modal = wrapper.findComponent(GlModal);
});
- it('renders the defaultBranchName copy', () => {
- expect(findCopyString().text()).toContain('- main');
+ it('displays instructions', () => {
+ expect(findInstructions().length).toBe(7);
+ expect(findInstructionAt(0).text()).toContain(i18n.instructions.step1);
+ });
+
+ it('renders the snippet to copy', () => {
+ expect(findCopyString().text()).toBe(wrapper.vm.modalInfoCopyStr);
});
it('renders the copyToClipboard button', () => {
expect(wrapper.findComponent(ModalCopyButton).props()).toMatchObject({
modalId: 'fake-id',
target: `#${EXPECTED_COPY_PRE_ID}`,
- title: 'Copy snippet text',
+ title: i18n.copyToClipboardText,
});
});
diff --git a/spec/frontend/environments/environment_external_url_spec.js b/spec/frontend/environments/environment_external_url_spec.js
index 4c133665979..5966993166b 100644
--- a/spec/frontend/environments/environment_external_url_spec.js
+++ b/spec/frontend/environments/environment_external_url_spec.js
@@ -1,16 +1,35 @@
import { mount } from '@vue/test-utils';
+import { s__, __ } from '~/locale';
import ExternalUrlComp from '~/environments/components/environment_external_url.vue';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
describe('External URL Component', () => {
let wrapper;
- const externalUrl = 'https://gitlab.com';
+ let externalUrl;
- beforeEach(() => {
- wrapper = mount(ExternalUrlComp, { propsData: { externalUrl } });
+ describe('with safe link', () => {
+ beforeEach(() => {
+ externalUrl = 'https://gitlab.com';
+ wrapper = mount(ExternalUrlComp, { propsData: { externalUrl } });
+ });
+
+ it('should link to the provided externalUrl prop', () => {
+ expect(wrapper.attributes('href')).toBe(externalUrl);
+ expect(wrapper.find('a').exists()).toBe(true);
+ });
});
- it('should link to the provided externalUrl prop', () => {
- expect(wrapper.attributes('href')).toEqual(externalUrl);
- expect(wrapper.find('a').exists()).toBe(true);
+ describe('with unsafe link', () => {
+ beforeEach(() => {
+ externalUrl = 'postgres://gitlab';
+ wrapper = mount(ExternalUrlComp, { propsData: { externalUrl } });
+ });
+
+ it('should show a copy button instead', () => {
+ const button = wrapper.findComponent(ModalCopyButton);
+ expect(button.props('text')).toBe(externalUrl);
+ expect(button.text()).toBe(__('Copy URL'));
+ expect(button.props('title')).toBe(s__('Environments|Copy live environment URL'));
+ });
});
});
diff --git a/spec/frontend/environments/environment_folder_spec.js b/spec/frontend/environments/environment_folder_spec.js
index 48624f2324b..a37515bc3f7 100644
--- a/spec/frontend/environments/environment_folder_spec.js
+++ b/spec/frontend/environments/environment_folder_spec.js
@@ -31,6 +31,7 @@ describe('~/environments/components/environments_folder.vue', () => {
apolloProvider,
propsData: {
scope: 'available',
+ search: '',
...propsData,
},
stubs: { transition: stubTransition() },
@@ -137,13 +138,26 @@ describe('~/environments/components/environments_folder.vue', () => {
expect(environmentFolderMock).toHaveBeenCalledTimes(1);
expect(environmentFolderMock).toHaveBeenCalledWith(
{},
- {
- environment: nestedEnvironment.latest,
- scope,
- },
+ expect.objectContaining({ scope }),
expect.anything(),
expect.anything(),
);
},
);
+
+ it('should query for the entered parameter', async () => {
+ const search = 'hello';
+
+ wrapper = createWrapper({ nestedEnvironment, search }, createApolloProvider());
+
+ await nextTick();
+ await waitForPromises();
+
+ expect(environmentFolderMock).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ search }),
+ expect.anything(),
+ expect.anything(),
+ );
+ });
});
diff --git a/spec/frontend/environments/environments_app_spec.js b/spec/frontend/environments/environments_app_spec.js
index aff54107d6b..65a9f2907d2 100644
--- a/spec/frontend/environments/environments_app_spec.js
+++ b/spec/frontend/environments/environments_app_spec.js
@@ -71,7 +71,7 @@ describe('~/environments/components/environments_app.vue', () => {
previousPage: 1,
__typename: 'LocalPageInfo',
},
- location = '?scope=available&page=2',
+ location = '?scope=available&page=2&search=prod',
}) => {
setWindowLocation(location);
environmentAppMock.mockReturnValue(environmentsApp);
@@ -104,7 +104,7 @@ describe('~/environments/components/environments_app.vue', () => {
await createWrapperWithMocked({
environmentsApp: resolvedEnvironmentsApp,
folder: resolvedFolder,
- location: '?scope=bad&page=2',
+ location: '?scope=bad&page=2&search=prod',
});
expect(environmentAppMock).toHaveBeenCalledWith(
@@ -350,7 +350,54 @@ describe('~/environments/components/environments_app.vue', () => {
next.trigger('click');
await nextTick();
- expect(window.location.search).toBe('?scope=available&page=3');
+ expect(window.location.search).toBe('?scope=available&page=3&search=prod');
+ });
+ });
+
+ describe('search', () => {
+ let searchBox;
+
+ const waitForDebounce = async () => {
+ await nextTick();
+ jest.runOnlyPendingTimers();
+ };
+
+ beforeEach(async () => {
+ await createWrapperWithMocked({
+ environmentsApp: resolvedEnvironmentsApp,
+ folder: resolvedFolder,
+ });
+ searchBox = wrapper.findByRole('searchbox', {
+ name: s__('Environments|Search by environment name'),
+ });
+ });
+
+ it('should sync the query params to the new search', async () => {
+ searchBox.setValue('hello');
+
+ await waitForDebounce();
+
+ expect(window.location.search).toBe('?scope=available&page=1&search=hello');
+ });
+
+ it('should query for the entered parameter', async () => {
+ const search = 'hello';
+
+ searchBox.setValue(search);
+
+ await waitForDebounce();
+ await waitForPromises();
+
+ expect(environmentAppMock).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ search }),
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+
+ it('should sync search term from query params on load', async () => {
+ expect(searchBox.element.value).toBe('prod');
});
});
});
diff --git a/spec/frontend/environments/environments_detail_header_spec.js b/spec/frontend/environments/environments_detail_header_spec.js
index 4687119127d..1f233c05fbf 100644
--- a/spec/frontend/environments/environments_detail_header_spec.js
+++ b/spec/frontend/environments/environments_detail_header_spec.js
@@ -1,10 +1,12 @@
import { GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { __, s__ } from '~/locale';
import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue';
import EnvironmentsDetailHeader from '~/environments/components/environments_detail_header.vue';
import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
import { createEnvironment } from './mock_data';
describe('Environments detail header component', () => {
@@ -243,4 +245,23 @@ describe('Environments detail header component', () => {
expect(findDeleteEnvironmentModal().exists()).toBe(true);
});
});
+
+ describe('when the environment has an unsafe external url', () => {
+ const externalUrl = 'postgres://staging';
+
+ beforeEach(() => {
+ createWrapper({
+ props: {
+ environment: createEnvironment({ externalUrl }),
+ },
+ });
+ });
+
+ it('should show a copy button instead', () => {
+ const button = wrapper.findComponent(ModalCopyButton);
+ expect(button.props('title')).toBe(s__('Environments|Copy live environment URL'));
+ expect(button.props('text')).toBe(externalUrl);
+ expect(button.text()).toBe(__('Copy URL'));
+ });
+ });
});
diff --git a/spec/frontend/environments/graphql/resolvers_spec.js b/spec/frontend/environments/graphql/resolvers_spec.js
index 26f0659204a..7684cca2303 100644
--- a/spec/frontend/environments/graphql/resolvers_spec.js
+++ b/spec/frontend/environments/graphql/resolvers_spec.js
@@ -41,11 +41,16 @@ describe('~/frontend/environments/graphql/resolvers', () => {
it('should fetch environments and map them to frontend data', async () => {
const cache = { writeQuery: jest.fn() };
const scope = 'available';
+ const search = '';
mock
- .onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
+ .onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search } })
.reply(200, environmentsApp, {});
- const app = await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
+ const app = await mockResolvers.Query.environmentApp(
+ null,
+ { scope, page: 1, search },
+ { cache },
+ );
expect(app).toEqual(resolvedEnvironmentsApp);
expect(cache.writeQuery).toHaveBeenCalledWith({
query: pollIntervalQuery,
@@ -57,12 +62,12 @@ describe('~/frontend/environments/graphql/resolvers', () => {
const scope = 'stopped';
const interval = 3000;
mock
- .onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
+ .onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
.reply(200, environmentsApp, {
'poll-interval': interval,
});
- await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
+ await mockResolvers.Query.environmentApp(null, { scope, page: 1, search: '' }, { cache });
expect(cache.writeQuery).toHaveBeenCalledWith({
query: pollIntervalQuery,
data: { interval },
@@ -72,7 +77,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
const cache = { writeQuery: jest.fn() };
const scope = 'stopped';
mock
- .onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
+ .onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
.reply(200, environmentsApp, {
'x-next-page': '2',
'x-page': '1',
@@ -82,7 +87,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
'X-Total-Pages': '5',
});
- await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
+ await mockResolvers.Query.environmentApp(null, { scope, page: 1, search: '' }, { cache });
expect(cache.writeQuery).toHaveBeenCalledWith({
query: pageInfoQuery,
data: {
@@ -102,10 +107,10 @@ describe('~/frontend/environments/graphql/resolvers', () => {
const cache = { writeQuery: jest.fn() };
const scope = 'stopped';
mock
- .onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
+ .onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
.reply(200, environmentsApp, {});
- await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
+ await mockResolvers.Query.environmentApp(null, { scope, page: 1, search: '' }, { cache });
expect(cache.writeQuery).toHaveBeenCalledWith({
query: pageInfoQuery,
data: {
@@ -124,11 +129,14 @@ describe('~/frontend/environments/graphql/resolvers', () => {
});
describe('folder', () => {
it('should fetch the folder url passed to it', async () => {
- mock.onGet(ENDPOINT, { params: { per_page: 3, scope: 'available' } }).reply(200, folder);
+ mock
+ .onGet(ENDPOINT, { params: { per_page: 3, scope: 'available', search: '' } })
+ .reply(200, folder);
const environmentFolder = await mockResolvers.Query.folder(null, {
environment: { folderPath: ENDPOINT },
scope: 'available',
+ search: '',
});
expect(environmentFolder).toEqual(resolvedFolder);
diff --git a/spec/frontend/environments/new_environment_spec.js b/spec/frontend/environments/new_environment_spec.js
index 2405cb82eac..6dd4eea7437 100644
--- a/spec/frontend/environments/new_environment_spec.js
+++ b/spec/frontend/environments/new_environment_spec.js
@@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import NewEnvironment from '~/environments/components/new_environment.vue';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
@@ -94,7 +94,7 @@ describe('~/environments/components/new.vue', () => {
await submitForm(expected, [400, { message: ['name taken'] }]);
- expect(createFlash).toHaveBeenCalledWith({ message: 'name taken' });
+ expect(createAlert).toHaveBeenCalledWith({ message: 'name taken' });
expect(showsLoading()).toBe(false);
});
});