2022-05-07 20:08:51 +05:30
|
|
|
import Vue, { nextTick } from 'vue';
|
|
|
|
import VueApollo from 'vue-apollo';
|
|
|
|
import { GlPagination } from '@gitlab/ui';
|
|
|
|
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
|
|
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
|
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
|
|
|
import setWindowLocation from 'helpers/set_window_location_helper';
|
|
|
|
import { sprintf, __, s__ } from '~/locale';
|
2020-04-08 14:13:33 +05:30
|
|
|
import EnvironmentsApp from '~/environments/components/environments_app.vue';
|
2022-05-07 20:08:51 +05:30
|
|
|
import EnvironmentsFolder from '~/environments/components/environment_folder.vue';
|
|
|
|
import EnvironmentsItem from '~/environments/components/new_environment_item.vue';
|
|
|
|
import EmptyState from '~/environments/components/empty_state.vue';
|
|
|
|
import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue';
|
|
|
|
import CanaryUpdateModal from '~/environments/components/canary_update_modal.vue';
|
|
|
|
import { resolvedEnvironmentsApp, resolvedFolder, resolvedEnvironment } from './graphql/mock_data';
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
Vue.use(VueApollo);
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('~/environments/components/environments_app.vue', () => {
|
|
|
|
let wrapper;
|
|
|
|
let environmentAppMock;
|
|
|
|
let environmentFolderMock;
|
|
|
|
let paginationMock;
|
|
|
|
let environmentToStopMock;
|
|
|
|
let environmentToChangeCanaryMock;
|
|
|
|
let weightMock;
|
|
|
|
|
|
|
|
const createApolloProvider = () => {
|
|
|
|
const mockResolvers = {
|
|
|
|
Query: {
|
|
|
|
environmentApp: environmentAppMock,
|
|
|
|
folder: environmentFolderMock,
|
|
|
|
pageInfo: paginationMock,
|
|
|
|
environmentToStop: environmentToStopMock,
|
|
|
|
environmentToDelete: jest.fn().mockResolvedValue(resolvedEnvironment),
|
|
|
|
environmentToRollback: jest.fn().mockResolvedValue(resolvedEnvironment),
|
|
|
|
environmentToChangeCanary: environmentToChangeCanaryMock,
|
|
|
|
weight: weightMock,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
return createMockApollo([], mockResolvers);
|
2020-04-08 14:13:33 +05:30
|
|
|
};
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const createWrapper = ({ provide = {}, apolloProvider } = {}) =>
|
|
|
|
mountExtended(EnvironmentsApp, {
|
|
|
|
provide: {
|
|
|
|
newEnvironmentPath: '/environments/new',
|
|
|
|
canCreateEnvironment: true,
|
|
|
|
defaultBranchName: 'main',
|
|
|
|
helpPagePath: '/help',
|
|
|
|
projectId: '1',
|
2022-10-11 01:57:18 +05:30
|
|
|
projectPath: '/1',
|
2022-05-07 20:08:51 +05:30
|
|
|
...provide,
|
|
|
|
},
|
|
|
|
apolloProvider,
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const createWrapperWithMocked = async ({
|
|
|
|
provide = {},
|
|
|
|
environmentsApp,
|
|
|
|
folder,
|
|
|
|
environmentToStop = {},
|
|
|
|
environmentToChangeCanary = {},
|
|
|
|
weight = 0,
|
|
|
|
pageInfo = {
|
|
|
|
total: 20,
|
|
|
|
perPage: 5,
|
|
|
|
nextPage: 3,
|
|
|
|
page: 2,
|
|
|
|
previousPage: 1,
|
|
|
|
__typename: 'LocalPageInfo',
|
|
|
|
},
|
2022-11-25 23:54:43 +05:30
|
|
|
location = '?scope=available&page=2&search=prod',
|
2022-05-07 20:08:51 +05:30
|
|
|
}) => {
|
|
|
|
setWindowLocation(location);
|
|
|
|
environmentAppMock.mockReturnValue(environmentsApp);
|
|
|
|
environmentFolderMock.mockReturnValue(folder);
|
|
|
|
paginationMock.mockReturnValue(pageInfo);
|
|
|
|
environmentToStopMock.mockReturnValue(environmentToStop);
|
|
|
|
environmentToChangeCanaryMock.mockReturnValue(environmentToChangeCanary);
|
|
|
|
weightMock.mockReturnValue(weight);
|
|
|
|
const apolloProvider = createApolloProvider();
|
|
|
|
wrapper = createWrapper({ apolloProvider, provide });
|
|
|
|
|
|
|
|
await waitForPromises();
|
|
|
|
await nextTick();
|
2020-04-08 14:13:33 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
beforeEach(() => {
|
2022-05-07 20:08:51 +05:30
|
|
|
environmentAppMock = jest.fn();
|
|
|
|
environmentFolderMock = jest.fn();
|
|
|
|
environmentToStopMock = jest.fn();
|
|
|
|
environmentToChangeCanaryMock = jest.fn();
|
|
|
|
weightMock = jest.fn();
|
|
|
|
paginationMock = jest.fn();
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should request available environments if the scope is invalid', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2022-11-25 23:54:43 +05:30
|
|
|
location: '?scope=bad&page=2&search=prod',
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
expect.objectContaining({ scope: 'available', page: 2 }),
|
|
|
|
expect.anything(),
|
|
|
|
expect.anything(),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should show all the folders that are fetched', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const text = wrapper.findAllComponents(EnvironmentsFolder).wrappers.map((w) => w.text());
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(text).toContainEqual(expect.stringMatching('review'));
|
|
|
|
expect(text).not.toContainEqual(expect.stringMatching('production'));
|
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should show all the environments that are fetched', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const text = wrapper.findAllComponents(EnvironmentsItem).wrappers.map((w) => w.text());
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(text).not.toContainEqual(expect.stringMatching('review'));
|
|
|
|
expect(text).toContainEqual(expect.stringMatching('production'));
|
|
|
|
});
|
2021-03-08 18:12:59 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should show an empty state with no environments', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: { ...resolvedEnvironmentsApp, environments: [] },
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
expect(wrapper.findComponent(EmptyState).exists()).toBe(true);
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should show a button to create a new environment', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const button = wrapper.findByRole('link', { name: s__('Environments|New environment') });
|
|
|
|
expect(button.attributes('href')).toBe('/environments/new');
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should not show a button to create a new environment if the user has no permissions', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
provide: { canCreateEnvironment: false, newEnvironmentPath: '' },
|
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const button = wrapper.findByRole('link', { name: s__('Environments|New environment') });
|
|
|
|
expect(button.exists()).toBe(false);
|
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should show a button to open the review app modal', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
const button = wrapper.findByRole('button', { name: s__('Environments|Enable review apps') });
|
|
|
|
expect(button.exists()).toBe(true);
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should not show a button to open the review app modal if review apps are configured', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: {
|
|
|
|
...resolvedEnvironmentsApp,
|
|
|
|
reviewApp: { canSetupReviewApp: false },
|
|
|
|
},
|
|
|
|
folder: resolvedFolder,
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
const button = wrapper.findByRole('button', { name: s__('Environments|Enable review apps') });
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(button.exists()).toBe(false);
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
it('should not show a button to clean up environments if the user has no permissions', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: {
|
|
|
|
...resolvedEnvironmentsApp,
|
|
|
|
canStopStaleEnvironments: false,
|
|
|
|
},
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
|
|
|
|
const button = wrapper.findByRole('button', {
|
|
|
|
name: s__('Environments|Clean up environments'),
|
|
|
|
});
|
|
|
|
expect(button.exists()).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should show a button to clean up environments if the user has permissions', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: {
|
|
|
|
...resolvedEnvironmentsApp,
|
|
|
|
canStopStaleEnvironments: true,
|
|
|
|
},
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
|
|
|
|
const button = wrapper.findByRole('button', {
|
|
|
|
name: s__('Environments|Clean up environments'),
|
|
|
|
});
|
|
|
|
expect(button.exists()).toBe(true);
|
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('tabs', () => {
|
|
|
|
it('should show tabs for available and stopped environmets', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const [available, stopped] = wrapper.findAllByRole('tab').wrappers;
|
|
|
|
|
|
|
|
expect(available.text()).toContain(__('Available'));
|
2022-08-13 15:12:31 +05:30
|
|
|
expect(available.text()).toContain(resolvedEnvironmentsApp.availableCount.toString());
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(stopped.text()).toContain(__('Stopped'));
|
2022-08-13 15:12:31 +05:30
|
|
|
expect(stopped.text()).toContain(resolvedEnvironmentsApp.stoppedCount.toString());
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
it('should change the requested scope on tab change', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
const stopped = wrapper.findByRole('tab', {
|
|
|
|
name: `${__('Stopped')} ${resolvedEnvironmentsApp.stoppedCount}`,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
stopped.trigger('click');
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
expect.objectContaining({ scope: 'stopped', page: 1 }),
|
|
|
|
expect.anything(),
|
|
|
|
expect.anything(),
|
|
|
|
);
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('modals', () => {
|
|
|
|
it('should pass the environment to stop to the stop environment modal', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
environmentToStop: resolvedEnvironment,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const modal = wrapper.findComponent(StopEnvironmentModal);
|
|
|
|
|
|
|
|
expect(modal.props('environment')).toMatchObject(resolvedEnvironment);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should pass the environment to change canary to the canary update modal', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
environmentToChangeCanary: resolvedEnvironment,
|
|
|
|
weight: 10,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
const modal = wrapper.findComponent(CanaryUpdateModal);
|
|
|
|
|
|
|
|
expect(modal.props('environment')).toMatchObject(resolvedEnvironment);
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
describe('pagination', () => {
|
|
|
|
it('should sync page from query params on load', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
expect(wrapper.findComponent(GlPagination).props('value')).toBe(2);
|
|
|
|
});
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should change the requested page on next page click', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
const next = wrapper.findByRole('link', {
|
|
|
|
name: __('Go to next page'),
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
next.trigger('click');
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
expect.objectContaining({ page: 3 }),
|
|
|
|
expect.anything(),
|
|
|
|
expect.anything(),
|
|
|
|
);
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should change the requested page on previous page click', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
const prev = wrapper.findByRole('link', {
|
|
|
|
name: __('Go to previous page'),
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
prev.trigger('click');
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
expect.objectContaining({ page: 1 }),
|
|
|
|
expect.anything(),
|
|
|
|
expect.anything(),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should change the requested page on specific page click', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
const page = 1;
|
|
|
|
const pageButton = wrapper.findByRole('link', {
|
|
|
|
name: sprintf(__('Go to page %{page}'), { page }),
|
2021-01-03 14:25:43 +05:30
|
|
|
});
|
2021-09-30 23:02:18 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
pageButton.trigger('click');
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
expect.objectContaining({ page }),
|
|
|
|
expect.anything(),
|
|
|
|
expect.anything(),
|
|
|
|
);
|
2021-09-30 23:02:18 +05:30
|
|
|
});
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
it('should sync the query params to the new page', async () => {
|
|
|
|
await createWrapperWithMocked({
|
|
|
|
environmentsApp: resolvedEnvironmentsApp,
|
|
|
|
folder: resolvedFolder,
|
|
|
|
});
|
|
|
|
const next = wrapper.findByRole('link', {
|
|
|
|
name: __('Go to next page'),
|
|
|
|
});
|
|
|
|
|
|
|
|
next.trigger('click');
|
|
|
|
|
|
|
|
await nextTick();
|
2022-11-25 23:54:43 +05:30
|
|
|
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(),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2023-06-20 00:43:36 +05:30
|
|
|
it('should sync search term from query params on load', () => {
|
2022-11-25 23:54:43 +05:30
|
|
|
expect(searchBox.element.value).toBe('prod');
|
2021-09-30 23:02:18 +05:30
|
|
|
});
|
|
|
|
});
|
2020-04-08 14:13:33 +05:30
|
|
|
});
|