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:
Diffstat (limited to 'spec/frontend/ci')
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js27
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js69
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js27
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js69
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js25
-rw-r--r--spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js124
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js10
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js19
-rw-r--r--spec/frontend/ci/pipeline_editor/mock_data.js13
-rw-r--r--spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js170
-rw-r--r--spec/frontend/ci/pipeline_new/mock_data.js8
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js61
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js15
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/mock_data.js13
-rw-r--r--spec/frontend/ci/runner/admin_runners/provide_spec.js34
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js5
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_token_spec.js11
-rw-r--r--spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js13
-rw-r--r--spec/frontend/ci/runner/mock_data.js9
-rw-r--r--spec/frontend/ci/runner/runner_search_utils_spec.js3
21 files changed, 398 insertions, 331 deletions
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
index b364f098a3a..567a49d663c 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
@@ -30,7 +30,6 @@ describe('Ci Group Variable wrapper', () => {
provide: {
...mockProvide,
glFeatures: {
- ciGroupEnvScopeGraphql: false,
groupScopedCiVariables: false,
...featureFlags,
},
@@ -61,6 +60,10 @@ describe('Ci Group Variable wrapper', () => {
lookup: expect.any(Function),
query: getGroupVariables,
},
+ environments: {
+ lookup: expect.any(Function),
+ query: getGroupEnvironments,
+ },
},
refetchAfterMutation: false,
});
@@ -88,26 +91,4 @@ describe('Ci Group Variable wrapper', () => {
});
});
});
-
- describe('ciGroupEnvScopeGraphql feature flag', () => {
- describe('When enabled', () => {
- beforeEach(() => {
- createComponent({ featureFlags: { ciGroupEnvScopeGraphql: true } });
- });
-
- it('Passes down environments query to variable shared component', () => {
- expect(findCiShared().props('queryData').environments.query).toBe(getGroupEnvironments);
- });
- });
-
- describe('When disabled', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('Does not pass down environments query to variable shared component', () => {
- expect(findCiShared().props('queryData').environments).toBe(undefined);
- });
- });
- });
});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
new file mode 100644
index 00000000000..762c9611dac
--- /dev/null
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
@@ -0,0 +1,69 @@
+import { GlDrawer, GlFormSelect } from '@gitlab/ui';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import CiVariableDrawer from '~/ci/ci_variable_list/components/ci_variable_drawer.vue';
+import {
+ ADD_VARIABLE_ACTION,
+ variableOptions,
+ variableTypes,
+} from '~/ci/ci_variable_list/constants';
+
+describe('CI Variable Drawer', () => {
+ let wrapper;
+
+ const defaultProps = {
+ areEnvironmentsLoading: false,
+ hasEnvScopeQuery: true,
+ mode: ADD_VARIABLE_ACTION,
+ };
+
+ const createComponent = ({ mountFn = shallowMountExtended, props = {} } = {}) => {
+ wrapper = mountFn(CiVariableDrawer, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ environmentScopeLink: '/help/environments',
+ },
+ });
+ };
+
+ const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findTypeDropdown = () => wrapper.findComponent(GlFormSelect);
+
+ describe('validations', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mountExtended });
+ });
+
+ describe('type dropdown', () => {
+ it('adds each type option as a dropdown item', () => {
+ expect(findTypeDropdown().findAll('option')).toHaveLength(variableOptions.length);
+
+ variableOptions.forEach((v) => {
+ expect(findTypeDropdown().text()).toContain(v.text);
+ });
+ });
+
+ it('is set to environment variable by default', () => {
+ expect(findTypeDropdown().findAll('option').at(0).attributes('value')).toBe(
+ variableTypes.envType,
+ );
+ });
+ });
+ });
+
+ describe('drawer events', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('emits `close-form` when closing the drawer', async () => {
+ expect(wrapper.emitted('close-form')).toBeUndefined();
+
+ await findDrawer().vm.$emit('close');
+
+ expect(wrapper.emitted('close-form')).toHaveLength(1);
+ });
+ });
+});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
index d843646df16..7dce23f72c0 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlFormInput } from '@gitlab/ui';
+import { GlButton, GlFormInput, GlSprintf } from '@gitlab/ui';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import CiEnvironmentsDropdown from '~/ci/ci_variable_list/components/ci_environments_dropdown.vue';
@@ -10,6 +10,8 @@ import {
EVENT_LABEL,
EVENT_ACTION,
ENVIRONMENT_SCOPE_LINK_TITLE,
+ AWS_TIP_TITLE,
+ AWS_TIP_MESSAGE,
groupString,
instanceString,
projectString,
@@ -28,10 +30,6 @@ describe('Ci variable modal', () => {
const mockVariables = mockVariablesWithScopes(instanceString);
const defaultProvide = {
- awsLogoSvgPath: '/logo',
- awsTipCommandsLink: '/tips',
- awsTipDeployLink: '/deploy',
- awsTipLearnLink: '/learn-link',
containsVariableReferenceLink: '/reference',
environmentScopeLink: '/help/environments',
glFeatures: {
@@ -122,9 +120,9 @@ describe('Ci variable modal', () => {
expect(wrapper.emitted('add-variable')).toEqual([[currentVariable]]);
});
- it('Dispatches the `hideModal` event when dismissing', () => {
+ it('Dispatches the `close-form` event when dismissing', () => {
findModal().vm.$emit('hidden');
- expect(wrapper.emitted('hideModal')).toEqual([[]]);
+ expect(wrapper.emitted('close-form')).toEqual([[]]);
});
});
});
@@ -171,7 +169,7 @@ describe('Ci variable modal', () => {
it('does not show AWS guidance tip', () => {
const tip = findAWSTip();
- expect(tip.exists()).toBe(true);
+
expect(tip.isVisible()).toBe(false);
});
});
@@ -184,13 +182,18 @@ describe('Ci variable modal', () => {
key: AWS_ACCESS_KEY_ID,
value: 'AKIAIOSFODNN7EXAMPLEjdhy',
};
- createComponent({ mountFn: mountExtended, props: { selectedVariable: AWSKeyVariable } });
+ createComponent({
+ mountFn: shallowMountExtended,
+ props: { selectedVariable: AWSKeyVariable },
+ });
});
it('shows AWS guidance tip', () => {
const tip = findAWSTip();
- expect(tip.exists()).toBe(true);
+
expect(tip.isVisible()).toBe(true);
+ expect(tip.props('title')).toBe(AWS_TIP_TITLE);
+ expect(tip.findComponent(GlSprintf).attributes('message')).toBe(AWS_TIP_MESSAGE);
});
});
@@ -313,9 +316,9 @@ describe('Ci variable modal', () => {
expect(wrapper.emitted('update-variable')).toEqual([[variable]]);
});
- it('Propagates the `hideModal` event', () => {
+ it('Propagates the `close-form` event', () => {
findModal().vm.$emit('hidden');
- expect(wrapper.emitted('hideModal')).toEqual([[]]);
+ expect(wrapper.emitted('close-form')).toEqual([[]]);
});
it('dispatches `delete-variable` with correct variable to delete', () => {
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
index d72cfc5fc14..f5737c61eea 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
@@ -1,7 +1,9 @@
import { shallowMount } from '@vue/test-utils';
import CiVariableSettings from '~/ci/ci_variable_list/components/ci_variable_settings.vue';
-import ciVariableModal from '~/ci/ci_variable_list/components/ci_variable_modal.vue';
-import ciVariableTable from '~/ci/ci_variable_list/components/ci_variable_table.vue';
+import CiVariableModal from '~/ci/ci_variable_list/components/ci_variable_modal.vue';
+import CiVariableTable from '~/ci/ci_variable_list/components/ci_variable_table.vue';
+import CiVariableDrawer from '~/ci/ci_variable_list/components/ci_variable_drawer.vue';
+
import {
ADD_VARIABLE_ACTION,
EDIT_VARIABLE_ACTION,
@@ -27,15 +29,22 @@ describe('Ci variable table', () => {
variables: mockVariablesWithScopes(projectString),
};
- const findCiVariableTable = () => wrapper.findComponent(ciVariableTable);
- const findCiVariableModal = () => wrapper.findComponent(ciVariableModal);
+ const findCiVariableDrawer = () => wrapper.findComponent(CiVariableDrawer);
+ const findCiVariableTable = () => wrapper.findComponent(CiVariableTable);
+ const findCiVariableModal = () => wrapper.findComponent(CiVariableModal);
- const createComponent = ({ props = {} } = {}) => {
+ const createComponent = ({ props = {}, featureFlags = {} } = {}) => {
wrapper = shallowMount(CiVariableSettings, {
propsData: {
...defaultProps,
...props,
},
+ provide: {
+ glFeatures: {
+ ciVariableDrawer: false,
+ ...featureFlags,
+ },
+ },
});
};
@@ -70,51 +79,51 @@ describe('Ci variable table', () => {
});
});
- describe('modal mode', () => {
+ describe.each`
+ bool | flagStatus | elementName | findElement
+ ${false} | ${'disabled'} | ${'modal'} | ${findCiVariableModal}
+ ${true} | ${'enabled'} | ${'drawer'} | ${findCiVariableDrawer}
+ `('when ciVariableDrawer feature flag is $flagStatus', ({ bool, elementName, findElement }) => {
beforeEach(() => {
- createComponent();
+ createComponent({ featureFlags: { ciVariableDrawer: bool } });
});
- it('passes down ADD mode when receiving an empty variable', async () => {
- await findCiVariableTable().vm.$emit('set-selected-variable');
-
- expect(findCiVariableModal().props('mode')).toBe(ADD_VARIABLE_ACTION);
+ it(`${elementName} is hidden by default`, () => {
+ expect(findElement().exists()).toBe(false);
});
- it('passes down EDIT mode when receiving a variable', async () => {
- await findCiVariableTable().vm.$emit('set-selected-variable', newVariable);
+ it(`shows ${elementName} when adding a new variable`, async () => {
+ await findCiVariableTable().vm.$emit('set-selected-variable');
- expect(findCiVariableModal().props('mode')).toBe(EDIT_VARIABLE_ACTION);
+ expect(findElement().exists()).toBe(true);
});
- });
- describe('variable modal', () => {
- beforeEach(() => {
- createComponent();
- });
+ it(`shows ${elementName} when updating a variable`, async () => {
+ await findCiVariableTable().vm.$emit('set-selected-variable', newVariable);
- it('is hidden by default', () => {
- expect(findCiVariableModal().exists()).toBe(false);
+ expect(findElement().exists()).toBe(true);
});
- it('shows modal when adding a new variable', async () => {
+ it(`hides ${elementName} when closing the form`, async () => {
await findCiVariableTable().vm.$emit('set-selected-variable');
- expect(findCiVariableModal().exists()).toBe(true);
- });
+ expect(findElement().isVisible()).toBe(true);
- it('shows modal when updating a variable', async () => {
- await findCiVariableTable().vm.$emit('set-selected-variable', newVariable);
+ await findElement().vm.$emit('close-form');
- expect(findCiVariableModal().exists()).toBe(true);
+ expect(findElement().exists()).toBe(false);
});
- it('hides modal when receiving the event from the modal', async () => {
+ it(`passes down ADD mode to ${elementName} when receiving an empty variable`, async () => {
await findCiVariableTable().vm.$emit('set-selected-variable');
- await findCiVariableModal().vm.$emit('hideModal');
+ expect(findElement().props('mode')).toBe(ADD_VARIABLE_ACTION);
+ });
+
+ it(`passes down EDIT mode to ${elementName} when receiving a variable`, async () => {
+ await findCiVariableTable().vm.$emit('set-selected-variable', newVariable);
- expect(findCiVariableModal().exists()).toBe(false);
+ expect(findElement().props('mode')).toBe(EDIT_VARIABLE_ACTION);
});
});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
index f3f1c5bd2c5..39c03a41660 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
@@ -1,4 +1,4 @@
-import { GlAlert, GlBadge, GlKeysetPagination } from '@gitlab/ui';
+import { GlAlert, GlBadge, GlKeysetPagination, GlCard, GlIcon } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import CiVariableTable from '~/ci/ci_variable_list/components/ci_variable_table.vue';
@@ -36,7 +36,7 @@ describe('Ci variable table', () => {
};
const findRevealButton = () => wrapper.findByText('Reveal values');
- const findAddButton = () => wrapper.findByLabelText('Add');
+ const findAddButton = () => wrapper.findByTestId('add-ci-variable-button');
const findEditButton = () => wrapper.findByLabelText('Edit');
const findEmptyVariablesPlaceholder = () => wrapper.findByText('There are no variables yet.');
const findHiddenValues = () => wrapper.findAllByTestId('hiddenValue');
@@ -50,11 +50,30 @@ describe('Ci variable table', () => {
const findGroupCiCdSettingsLink = (rowIndex) =>
wrapper.findAllByTestId('ci-variable-table-row-cicd-path').at(rowIndex).attributes('href');
const findKeysetPagination = () => wrapper.findComponent(GlKeysetPagination);
+ const findCard = () => wrapper.findComponent(GlCard);
const generateExceedsVariableLimitText = (entity, currentVariableCount, maxVariableLimit) => {
return sprintf(EXCEEDS_VARIABLE_LIMIT_TEXT, { entity, currentVariableCount, maxVariableLimit });
};
+ describe('card', () => {
+ it('displays the correct title', () => {
+ createComponent();
+ expect(findCard().text()).toContain('CI/CD Variables');
+ });
+
+ it('displays the correct icon', () => {
+ createComponent();
+ expect(findCard().findComponent(GlIcon).props('name')).toBe('code');
+ });
+
+ it('displays the number of added CI/CD Variables', () => {
+ const variables = [1, 2, 3];
+ createComponent({ props: { variables } });
+ expect(findCard().text()).toContain(String(variables.length));
+ });
+ });
+
describe.each`
isVariablePagesEnabled | text
${true} | ${'enabled'}
@@ -88,7 +107,7 @@ describe('Ci variable table', () => {
${1} | ${'Value'}
${2} | ${'Attributes'}
${3} | ${'Environments'}
- ${4} | ${''}
+ ${4} | ${'Actions'}
`('renders the $text column', ({ index, text }) => {
expect(findTableColumnText(index)).toEqual(text);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
index 3a99949413b..4057759b9b9 100644
--- a/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
@@ -1,3 +1,5 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import {
GlDropdown,
GlDropdownItem,
@@ -5,8 +7,7 @@ import {
GlLoadingIcon,
GlSearchBoxByType,
} from '@gitlab/ui';
-import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
+import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import BranchSwitcher from '~/ci/pipeline_editor/components/file_nav/branch_switcher.vue';
@@ -17,10 +18,10 @@ import getLastCommitBranch from '~/ci/pipeline_editor/graphql/queries/client/las
import { resolvers } from '~/ci/pipeline_editor/graphql/resolvers';
import {
+ generateMockProjectBranches,
mockBranchPaginationLimit,
mockDefaultBranch,
mockEmptySearchBranches,
- mockProjectBranches,
mockProjectFullPath,
mockSearchBranches,
mockTotalBranches,
@@ -28,55 +29,14 @@ import {
mockTotalSearchResults,
} from '../../mock_data';
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
describe('Pipeline editor branch switcher', () => {
let wrapper;
let mockApollo;
let mockAvailableBranchQuery;
- const createComponent = ({
- currentBranch = mockDefaultBranch,
- availableBranches = ['main'],
- isQueryLoading = false,
- mountFn = shallowMount,
- options = {},
- props = {},
- } = {}) => {
- wrapper = mountFn(BranchSwitcher, {
- propsData: {
- ...props,
- paginationLimit: mockBranchPaginationLimit,
- },
- provide: {
- projectFullPath: mockProjectFullPath,
- totalBranches: mockTotalBranches,
- },
- mocks: {
- $apollo: {
- queries: {
- availableBranches: {
- loading: isQueryLoading,
- },
- },
- },
- },
- data() {
- return {
- availableBranches,
- currentBranch,
- };
- },
- ...options,
- });
- };
+ Vue.use(VueApollo);
- const createComponentWithApollo = ({
- mountFn = shallowMount,
- props = {},
- availableBranches = ['main'],
- } = {}) => {
+ const createComponent = ({ props = {} } = {}) => {
const handlers = [[getAvailableBranchesQuery, mockAvailableBranchQuery]];
mockApollo = createMockApollo(handlers, resolvers);
@@ -106,16 +66,19 @@ describe('Pipeline editor branch switcher', () => {
},
});
- createComponent({
- mountFn,
- props,
- availableBranches,
- options: {
- localVue,
- apolloProvider: mockApollo,
- mocks: {},
+ wrapper = shallowMount(BranchSwitcher, {
+ propsData: {
+ ...props,
+ paginationLimit: mockBranchPaginationLimit,
+ },
+ provide: {
+ projectFullPath: mockProjectFullPath,
+ totalBranches: mockTotalBranches,
},
+ apolloProvider: mockApollo,
});
+
+ return waitForPromises();
};
const findDropdown = () => wrapper.findComponent(GlDropdown);
@@ -137,7 +100,7 @@ describe('Pipeline editor branch switcher', () => {
expect(wrapper.emitted('showError')).toBeDefined();
expect(wrapper.emitted('showError')[0]).toEqual([
{
- reasons: [wrapper.vm.$options.i18n.fetchError],
+ reasons: ['Unable to fetch branch list for this project.'],
type: DEFAULT_FAILURE,
},
]);
@@ -145,19 +108,26 @@ describe('Pipeline editor branch switcher', () => {
describe('when querying for the first time', () => {
beforeEach(() => {
- createComponentWithApollo({ availableBranches: [] });
+ createComponent();
});
it('disables the dropdown', () => {
expect(findDropdown().props('disabled')).toBe(true);
});
+
+ it('shows loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
});
describe('after querying', () => {
beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
+ setAvailableBranchesMock(generateMockProjectBranches());
+ await createComponent();
+ });
+
+ it('does not render the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
});
it('renders search box', () => {
@@ -185,8 +155,7 @@ describe('Pipeline editor branch switcher', () => {
describe('on fetch error', () => {
beforeEach(async () => {
setAvailableBranchesMock(new Error());
- createComponentWithApollo({ availableBranches: [] });
- await waitForPromises();
+ await createComponent();
});
it('does not render dropdown', () => {
@@ -201,9 +170,8 @@ describe('Pipeline editor branch switcher', () => {
describe('when switching branches', () => {
beforeEach(async () => {
jest.spyOn(window.history, 'pushState').mockImplementation(() => {});
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
+ setAvailableBranchesMock(generateMockProjectBranches());
+ await createComponent();
});
it('updates session history when selecting a different branch', async () => {
@@ -251,7 +219,7 @@ describe('Pipeline editor branch switcher', () => {
describe('with unsaved changes', () => {
beforeEach(async () => {
- createComponentWithApollo({ mountFn: mount, props: { hasUnsavedChanges: true } });
+ createComponent({ props: { hasUnsavedChanges: true } });
await waitForPromises();
});
@@ -269,9 +237,8 @@ describe('Pipeline editor branch switcher', () => {
describe('when searching', () => {
beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo({ mountFn: mount });
- await waitForPromises();
+ setAvailableBranchesMock(generateMockProjectBranches());
+ await createComponent();
});
afterEach(() => {
@@ -329,7 +296,7 @@ describe('Pipeline editor branch switcher', () => {
findSearchBox().vm.$emit('input', 'te');
await waitForPromises();
- mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
+ mockAvailableBranchQuery.mockResolvedValue(generateMockProjectBranches());
});
it('calls query with correct variables', async () => {
@@ -355,23 +322,10 @@ describe('Pipeline editor branch switcher', () => {
});
});
- describe('loading icon', () => {
- it.each`
- isQueryLoading | isRendered
- ${true} | ${true}
- ${false} | ${false}
- `('checks if query is loading before rendering', ({ isQueryLoading, isRendered }) => {
- createComponent({ isQueryLoading, mountFn: mount });
-
- expect(findLoadingIcon().exists()).toBe(isRendered);
- });
- });
-
describe('when scrolling to the bottom of the list', () => {
beforeEach(async () => {
- setAvailableBranchesMock(mockProjectBranches);
- createComponentWithApollo();
- await waitForPromises();
+ setAvailableBranchesMock(generateMockProjectBranches());
+ await createComponent();
});
afterEach(() => {
@@ -382,6 +336,7 @@ describe('Pipeline editor branch switcher', () => {
it('fetches more branches', async () => {
expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1);
+ setAvailableBranchesMock(generateMockProjectBranches('new-'));
findInfiniteScroll().vm.$emit('bottomReached');
await waitForPromises();
@@ -389,6 +344,7 @@ describe('Pipeline editor branch switcher', () => {
});
it('calls the query with the correct variables', async () => {
+ setAvailableBranchesMock(generateMockProjectBranches('new-'));
findInfiniteScroll().vm.$emit('bottomReached');
await waitForPromises();
diff --git a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
index 29759f828e4..f5e0b65d615 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineEditorMiniGraph from '~/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
+import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '~/ci/pipeline_editor/constants';
import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
@@ -41,7 +41,7 @@ describe('Pipeline Status', () => {
});
};
- const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+ const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
beforeEach(() => {
mockLinkedPipelinesQuery = jest.fn();
@@ -53,7 +53,7 @@ describe('Pipeline Status', () => {
});
it('renders pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(true);
+ expect(findLegacyPipelineMiniGraph().exists()).toBe(true);
});
});
@@ -63,7 +63,7 @@ describe('Pipeline Status', () => {
});
it('does not render pipeline mini graph', () => {
- expect(findPipelineMiniGraph().exists()).toBe(false);
+ expect(findLegacyPipelineMiniGraph().exists()).toBe(false);
});
});
@@ -85,7 +85,7 @@ describe('Pipeline Status', () => {
});
it('renders only the latest downstream pipelines', () => {
- expect(findPipelineMiniGraph().props('downstreamPipelines')).toHaveLength(1);
+ expect(findLegacyPipelineMiniGraph().props('downstreamPipelines')).toHaveLength(1);
});
});
diff --git a/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
index 9d93ba332e9..3bbe14adb88 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
@@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineStatus, { i18n } from '~/ci/pipeline_editor/components/header/pipeline_status.vue';
import getPipelineQuery from '~/ci/pipeline_editor/graphql/queries/pipeline.query.graphql';
-import GraphqlPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/graphql_pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
import PipelineEditorMiniGraph from '~/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
import { mockCommitSha, mockProjectPipeline, mockProjectFullPath } from '../../mock_data';
@@ -38,8 +38,9 @@ describe('Pipeline Status', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findGraphqlPipelineMiniGraph = () => wrapper.findComponent(GraphqlPipelineMiniGraph);
const findPipelineEditorMiniGraph = () => wrapper.findComponent(PipelineEditorMiniGraph);
+ const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+
const findPipelineId = () => wrapper.find('[data-testid="pipeline-id"]');
const findPipelineCommit = () => wrapper.find('[data-testid="pipeline-commit"]');
const findPipelineErrorMsg = () => wrapper.find('[data-testid="pipeline-error-msg"]');
@@ -142,18 +143,18 @@ describe('Pipeline Status', () => {
});
it.each`
- state | provide | showPipelineMiniGraph | showGraphqlPipelineMiniGraph
- ${true} | ${{ ciGraphqlPipelineMiniGraph: true }} | ${false} | ${true}
- ${false} | ${{}} | ${true} | ${false}
+ state | showLegacyPipelineMiniGraph | showPipelineMiniGraph
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${false}
`(
'renders the correct component when the feature flag is set to $state',
- async ({ provide, showPipelineMiniGraph, showGraphqlPipelineMiniGraph }) => {
- createComponentWithApollo(provide);
+ async ({ state, showLegacyPipelineMiniGraph, showPipelineMiniGraph }) => {
+ createComponentWithApollo({ ciGraphqlPipelineMiniGraph: state });
await waitForPromises();
- expect(findPipelineEditorMiniGraph().exists()).toBe(showPipelineMiniGraph);
- expect(findGraphqlPipelineMiniGraph().exists()).toBe(showGraphqlPipelineMiniGraph);
+ expect(findPipelineEditorMiniGraph().exists()).toBe(showLegacyPipelineMiniGraph);
+ expect(findPipelineMiniGraph().exists()).toBe(showPipelineMiniGraph);
},
);
});
diff --git a/spec/frontend/ci/pipeline_editor/mock_data.js b/spec/frontend/ci/pipeline_editor/mock_data.js
index a3294cdc269..007abde939f 100644
--- a/spec/frontend/ci/pipeline_editor/mock_data.js
+++ b/spec/frontend/ci/pipeline_editor/mock_data.js
@@ -1,5 +1,6 @@
import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/ci/pipeline_editor/constants';
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
+import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
export const commonOptions = {
ciConfigPath: '/ci/config',
@@ -295,7 +296,7 @@ export const mockEmptyCommitShaResults = {
},
};
-export const mockProjectBranches = {
+export const generateMockProjectBranches = (prefix = '') => ({
data: {
project: {
id: '1',
@@ -311,14 +312,14 @@ export const mockProjectBranches = {
'mock-feature',
'test-merge-request',
'staging',
- ],
+ ].map((branch) => `${prefix}${branch}`),
},
},
},
-};
+});
-export const mockTotalBranchResults =
- mockProjectBranches.data.project.repository.branchNames.length;
+export const mockTotalBranchResults = generateMockProjectBranches().data.project.repository
+ .branchNames.length;
export const mockSearchBranches = {
data: {
@@ -601,7 +602,7 @@ export const mockErrors = [
];
export const mockWarnings = [
- '"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"',
+ `"jobs:multi_project_job may allow multiple pipelines to run for a single action due to \`rules:when\` clause with no \`workflow:rules\` - read more: ${DOCS_URL_IN_EE_DIR}/ci/troubleshooting.html#pipeline-warnings"`,
];
export const mockCommitCreateResponse = {
diff --git a/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js b/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
index 576263d5418..ca5f80f331c 100644
--- a/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
+++ b/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
@@ -1,19 +1,19 @@
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import { GlButton, GlDrawer, GlModal } from '@gitlab/ui';
+import { GlButton, GlModal } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
-import CiEditorHeader from '~/ci/pipeline_editor/components/editor/ci_editor_header.vue';
import CommitSection from '~/ci/pipeline_editor/components/commit/commit_section.vue';
import PipelineEditorDrawer from '~/ci/pipeline_editor/components/drawer/pipeline_editor_drawer.vue';
import JobAssistantDrawer from '~/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue';
import PipelineEditorFileNav from '~/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue';
import PipelineEditorFileTree from '~/ci/pipeline_editor/components/file_tree/container.vue';
-import BranchSwitcher from '~/ci/pipeline_editor/components/file_nav/branch_switcher.vue';
import PipelineEditorHeader from '~/ci/pipeline_editor/components/header/pipeline_editor_header.vue';
import PipelineEditorTabs from '~/ci/pipeline_editor/components/pipeline_editor_tabs.vue';
import {
CREATE_TAB,
+ EDITOR_APP_DRAWER_HELP,
+ EDITOR_APP_DRAWER_JOB_ASSISTANT,
+ EDITOR_APP_DRAWER_NONE,
FILE_TREE_DISPLAY_KEY,
VALIDATE_TAB,
MERGED_TAB,
@@ -29,10 +29,9 @@ jest.mock('~/lib/utils/common_utils');
describe('Pipeline editor home wrapper', () => {
let wrapper;
- const createComponent = ({ props = {}, glFeatures = {}, data = {}, stubs = {} } = {}) => {
+ const createComponent = ({ props = {}, glFeatures = {}, stubs = {} } = {}) => {
wrapper = extendedWrapper(
shallowMount(PipelineEditorHome, {
- data: () => data,
propsData: {
ciConfigData: mockLintResponse,
ciFileContent: mockCiYml,
@@ -53,7 +52,6 @@ describe('Pipeline editor home wrapper', () => {
);
};
- const findBranchSwitcher = () => wrapper.findComponent(BranchSwitcher);
const findCommitSection = () => wrapper.findComponent(CommitSection);
const findFileNav = () => wrapper.findComponent(PipelineEditorFileNav);
const findModal = () => wrapper.findComponent(GlModal);
@@ -63,8 +61,16 @@ describe('Pipeline editor home wrapper', () => {
const findPipelineEditorHeader = () => wrapper.findComponent(PipelineEditorHeader);
const findPipelineEditorTabs = () => wrapper.findComponent(PipelineEditorTabs);
const findFileTreeBtn = () => wrapper.findByTestId('file-tree-toggle');
- const findHelpBtn = () => wrapper.findByTestId('drawer-toggle');
- const findJobAssistantBtn = () => wrapper.findByTestId('job-assistant-drawer-toggle');
+
+ const clickHelpBtn = async () => {
+ await findPipelineEditorDrawer().vm.$emit('switch-drawer', EDITOR_APP_DRAWER_HELP);
+ };
+ const clickJobAssistantBtn = async () => {
+ await findJobAssistantDrawer().vm.$emit('switch-drawer', EDITOR_APP_DRAWER_JOB_ASSISTANT);
+ };
+ const closeDrawer = async (finder) => {
+ await finder().vm.$emit('switch-drawer', EDITOR_APP_DRAWER_NONE);
+ };
afterEach(() => {
localStorage.clear();
@@ -103,11 +109,9 @@ describe('Pipeline editor home wrapper', () => {
});
});
describe('when `showSwitchBranchModal` value is true', () => {
- beforeEach(() => {
- createComponent({
- data: { showSwitchBranchModal: true },
- stubs: { PipelineEditorFileNav },
- });
+ beforeEach(async () => {
+ createComponent();
+ await findFileNav().vm.$emit('select-branch');
});
it('is visible', () => {
@@ -115,11 +119,11 @@ describe('Pipeline editor home wrapper', () => {
});
it('pass down `shouldLoadNewBranch` to the branch switcher when primary is selected', async () => {
- expect(findBranchSwitcher().props('shouldLoadNewBranch')).toBe(false);
+ expect(findFileNav().props('shouldLoadNewBranch')).toBe(false);
await findModal().vm.$emit('primary');
- expect(findBranchSwitcher().props('shouldLoadNewBranch')).toBe(true);
+ expect(findFileNav().props('shouldLoadNewBranch')).toBe(true);
});
it('closes the modal when secondary action is selected', async () => {
@@ -148,9 +152,7 @@ describe('Pipeline editor home wrapper', () => {
async ({ tab, shouldShow }) => {
expect(findCommitSection().exists()).toBe(true);
- findPipelineEditorTabs().vm.$emit('set-current-tab', tab);
-
- await nextTick();
+ await findPipelineEditorTabs().vm.$emit('set-current-tab', tab);
expect(findCommitSection().isVisible()).toBe(shouldShow);
},
@@ -159,12 +161,10 @@ describe('Pipeline editor home wrapper', () => {
it('shows the commit form again when coming back to the create tab', async () => {
expect(findCommitSection().isVisible()).toBe(true);
- findPipelineEditorTabs().vm.$emit('set-current-tab', MERGED_TAB);
- await nextTick();
+ await findPipelineEditorTabs().vm.$emit('set-current-tab', MERGED_TAB);
expect(findCommitSection().isVisible()).toBe(false);
- findPipelineEditorTabs().vm.$emit('set-current-tab', CREATE_TAB);
- await nextTick();
+ await findPipelineEditorTabs().vm.$emit('set-current-tab', CREATE_TAB);
expect(findCommitSection().isVisible()).toBe(true);
});
@@ -195,7 +195,9 @@ describe('Pipeline editor home wrapper', () => {
describe('when "walkthrough-popover-cta-clicked" is emitted from pipeline editor tabs', () => {
it('passes down `scrollToCommitForm=true` to commit section', async () => {
expect(findCommitSection().props('scrollToCommitForm')).toBe(false);
+
await findPipelineEditorTabs().vm.$emit('walkthrough-popover-cta-clicked');
+
expect(findCommitSection().props('scrollToCommitForm')).toBe(true);
});
});
@@ -204,6 +206,7 @@ describe('Pipeline editor home wrapper', () => {
it('passes down `scrollToCommitForm=false` to commit section', async () => {
await findPipelineEditorTabs().vm.$emit('walkthrough-popover-cta-clicked');
expect(findCommitSection().props('scrollToCommitForm')).toBe(true);
+
await findCommitSection().vm.$emit('scrolled-to-commit-form');
expect(findCommitSection().props('scrollToCommitForm')).toBe(false);
});
@@ -211,133 +214,49 @@ describe('Pipeline editor home wrapper', () => {
});
describe('help drawer', () => {
- const clickHelpBtn = async () => {
- findHelpBtn().vm.$emit('click');
- await nextTick();
- };
-
- it('hides the drawer by default', () => {
+ beforeEach(() => {
createComponent();
+ });
+ it('hides the drawer by default', () => {
expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
});
it('toggles the drawer on button click', async () => {
- createComponent({
- stubs: {
- CiEditorHeader,
- GlButton,
- GlDrawer,
- PipelineEditorTabs,
- PipelineEditorDrawer,
- },
- });
-
- await clickHelpBtn();
-
- expect(findPipelineEditorDrawer().props('isVisible')).toBe(true);
-
- await clickHelpBtn();
-
expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
- });
-
- it("closes the drawer through the drawer's close button", async () => {
- createComponent({
- stubs: {
- CiEditorHeader,
- GlButton,
- GlDrawer,
- PipelineEditorTabs,
- PipelineEditorDrawer,
- },
- });
await clickHelpBtn();
-
expect(findPipelineEditorDrawer().props('isVisible')).toBe(true);
- findPipelineEditorDrawer().findComponent(GlDrawer).vm.$emit('close');
- await nextTick();
-
+ await closeDrawer(findPipelineEditorDrawer);
expect(findPipelineEditorDrawer().props('isVisible')).toBe(false);
});
});
describe('job assistant drawer', () => {
- const clickHelpBtn = async () => {
- findHelpBtn().vm.$emit('click');
- await nextTick();
- };
- const clickJobAssistantBtn = async () => {
- findJobAssistantBtn().vm.$emit('click');
- await nextTick();
- };
-
- const stubs = {
- CiEditorHeader,
- GlButton,
- GlDrawer,
- PipelineEditorTabs,
- JobAssistantDrawer,
- };
-
- it('hides the job assistant drawer by default', () => {
+ beforeEach(() => {
createComponent({
glFeatures: {
ciJobAssistantDrawer: true,
},
});
+ });
+ it('hides the job assistant drawer by default', () => {
expect(findJobAssistantDrawer().props('isVisible')).toBe(false);
});
it('toggles the job assistant drawer on button click', async () => {
- createComponent({
- stubs,
- glFeatures: {
- ciJobAssistantDrawer: true,
- },
- });
-
- await clickJobAssistantBtn();
-
- expect(findJobAssistantDrawer().props('isVisible')).toBe(true);
-
- await clickJobAssistantBtn();
-
expect(findJobAssistantDrawer().props('isVisible')).toBe(false);
- });
-
- it("closes the job assistant drawer through the drawer's close button", async () => {
- createComponent({
- stubs,
- glFeatures: {
- ciJobAssistantDrawer: true,
- },
- });
await clickJobAssistantBtn();
-
expect(findJobAssistantDrawer().props('isVisible')).toBe(true);
- findJobAssistantDrawer().findComponent(GlDrawer).vm.$emit('close');
- await nextTick();
-
+ await closeDrawer(findJobAssistantDrawer);
expect(findJobAssistantDrawer().props('isVisible')).toBe(false);
});
it('covers helper drawer when opened last', async () => {
- createComponent({
- stubs: {
- ...stubs,
- PipelineEditorDrawer,
- },
- glFeatures: {
- ciJobAssistantDrawer: true,
- },
- });
-
await clickHelpBtn();
await clickJobAssistantBtn();
@@ -348,16 +267,6 @@ describe('Pipeline editor home wrapper', () => {
});
it('covered by helper drawer when opened first', async () => {
- createComponent({
- stubs: {
- ...stubs,
- PipelineEditorDrawer,
- },
- glFeatures: {
- ciJobAssistantDrawer: true,
- },
- });
-
await clickJobAssistantBtn();
await clickHelpBtn();
@@ -370,8 +279,7 @@ describe('Pipeline editor home wrapper', () => {
describe('file tree', () => {
const toggleFileTree = async () => {
- findFileTreeBtn().vm.$emit('click');
- await nextTick();
+ await findFileTreeBtn().vm.$emit('click');
};
describe('button toggle', () => {
@@ -412,9 +320,7 @@ describe('Pipeline editor home wrapper', () => {
describe('when file tree display state is saved in local storage', () => {
beforeEach(() => {
localStorage.setItem(FILE_TREE_DISPLAY_KEY, 'true');
- createComponent({
- stubs: { PipelineEditorFileNav },
- });
+ createComponent();
});
it('shows the file tree by default', () => {
@@ -424,9 +330,7 @@ describe('Pipeline editor home wrapper', () => {
describe('when file tree display state is not saved in local storage', () => {
beforeEach(() => {
- createComponent({
- stubs: { PipelineEditorFileNav },
- });
+ createComponent();
});
it('hides the file tree by default', () => {
diff --git a/spec/frontend/ci/pipeline_new/mock_data.js b/spec/frontend/ci/pipeline_new/mock_data.js
index 76a88f63298..72a491bb946 100644
--- a/spec/frontend/ci/pipeline_new/mock_data.js
+++ b/spec/frontend/ci/pipeline_new/mock_data.js
@@ -1,3 +1,5 @@
+import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
+
export const mockFilteredRefs = {
Branches: ['branch-1'],
Tags: ['1.0.0', '1.1.0'],
@@ -28,9 +30,9 @@ export const mockError = {
'test job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post',
],
warnings: [
- 'jobs:build1 may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings',
- 'jobs:build2 may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings',
- 'jobs:build3 may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings',
+ `jobs:build1 may allow multiple pipelines to run for a single action due to \`rules:when\` clause with no \`workflow:rules\` - read more: ${DOCS_URL_IN_EE_DIR}/ci/troubleshooting.html#pipeline-warnings`,
+ `jobs:build2 may allow multiple pipelines to run for a single action due to \`rules:when\` clause with no \`workflow:rules\` - read more: ${DOCS_URL_IN_EE_DIR}/ci/troubleshooting.html#pipeline-warnings`,
+ `jobs:build3 may allow multiple pipelines to run for a single action due to \`rules:when\` clause with no \`workflow:rules\` - read more: ${DOCS_URL_IN_EE_DIR}/ci/troubleshooting.html#pipeline-warnings`,
],
total_warnings: 7,
};
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
index bb48d4dc38d..79a0cfa0dc9 100644
--- a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
@@ -21,6 +21,7 @@ import {
createScheduleMutationResponse,
updateScheduleMutationResponse,
mockSinglePipelineScheduleNode,
+ mockSinglePipelineScheduleNodeNoVars,
} from '../mock_data';
Vue.use(VueApollo);
@@ -51,6 +52,9 @@ describe('Pipeline schedules form', () => {
const dailyLimit = '';
const querySuccessHandler = jest.fn().mockResolvedValue(mockSinglePipelineScheduleNode);
+ const querySuccessEmptyVarsHandler = jest
+ .fn()
+ .mockResolvedValue(mockSinglePipelineScheduleNodeNoVars);
const queryFailedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
const createMutationHandlerSuccess = jest.fn().mockResolvedValue(createScheduleMutationResponse);
@@ -95,6 +99,10 @@ describe('Pipeline schedules form', () => {
const findVariableRows = () => wrapper.findAllByTestId('ci-variable-row');
const findKeyInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-key');
const findValueInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-value');
+ const findHiddenValueInputs = () =>
+ wrapper.findAllByTestId('pipeline-form-ci-variable-hidden-value');
+ const findVariableSecurityBtn = () => wrapper.findByTestId('variable-security-btn');
+
const findRemoveIcons = () => wrapper.findAllByTestId('remove-ci-variable-row');
const addVariableToForm = () => {
@@ -241,6 +249,12 @@ describe('Pipeline schedules form', () => {
expect(findLoadingIcon().exists()).toBe(false);
});
+ it('does not show variable security button', () => {
+ createComponent();
+
+ expect(findVariableSecurityBtn().exists()).toBe(false);
+ });
+
describe('schedule creation success', () => {
let mock;
@@ -336,6 +350,26 @@ describe('Pipeline schedules form', () => {
expect(findLoadingIcon().exists()).toBe(false);
});
+ it('shows variable security button', async () => {
+ createComponent(shallowMountExtended, true, [
+ [getPipelineSchedulesQuery, querySuccessHandler],
+ ]);
+
+ await waitForPromises();
+
+ expect(findVariableSecurityBtn().exists()).toBe(true);
+ });
+
+ it('does not show variable security button with no present variables', async () => {
+ createComponent(shallowMountExtended, true, [
+ [getPipelineSchedulesQuery, querySuccessEmptyVarsHandler],
+ ]);
+
+ await waitForPromises();
+
+ expect(findVariableSecurityBtn().exists()).toBe(false);
+ });
+
describe('schedule fetch success', () => {
it('fetches schedule and sets form data correctly', async () => {
createComponent(mountExtended, true, [[getPipelineSchedulesQuery, querySuccessHandler]]);
@@ -351,8 +385,13 @@ describe('Pipeline schedules form', () => {
expect(findVariableRows()).toHaveLength(3);
expect(findKeyInputs().at(0).element.value).toBe(variables[0].key);
expect(findKeyInputs().at(1).element.value).toBe(variables[1].key);
- expect(findValueInputs().at(0).element.value).toBe(variables[0].value);
- expect(findValueInputs().at(1).element.value).toBe(variables[1].value);
+ // values are hidden on load when editing a schedule
+ expect(findHiddenValueInputs().at(0).element.value).toBe('*****************');
+ expect(findHiddenValueInputs().at(1).element.value).toBe('*****************');
+ expect(findHiddenValueInputs().at(0).attributes('disabled')).toBe('disabled');
+ expect(findHiddenValueInputs().at(1).attributes('disabled')).toBe('disabled');
+ // empty placeholder to create a new variable
+ expect(findValueInputs()).toHaveLength(1);
});
});
@@ -432,5 +471,23 @@ describe('Pipeline schedules form', () => {
message: 'An error occurred while updating the pipeline schedule.',
});
});
+
+ it('hides/shows variable values', async () => {
+ createComponent(mountExtended, true, [[getPipelineSchedulesQuery, querySuccessHandler]]);
+
+ await waitForPromises();
+
+ // shows two hidden values and one placeholder
+ expect(findHiddenValueInputs()).toHaveLength(2);
+ expect(findValueInputs()).toHaveLength(1);
+
+ findVariableSecurityBtn().vm.$emit('click');
+
+ await nextTick();
+
+ // shows all variable values
+ expect(findHiddenValueInputs()).toHaveLength(0);
+ expect(findValueInputs()).toHaveLength(3);
+ });
});
});
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
index 01a19711264..eb76b0bfbb4 100644
--- a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
@@ -3,6 +3,7 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { trimText } from 'helpers/text_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import PipelineSchedules from '~/ci/pipeline_schedules/components/pipeline_schedules.vue';
@@ -354,5 +355,19 @@ describe('Pipeline schedules app', () => {
expect(findLink().exists()).toBe(true);
expect(findLink().text()).toContain('scheduled pipelines documentation.');
});
+
+ describe('inactive tab', () => {
+ beforeEach(() => {
+ setWindowLocation('https://gitlab.com/flightjs/Flight/-/pipeline_schedules?scope=INACTIVE');
+ });
+
+ it('should not show empty state', async () => {
+ createComponent([[getPipelineSchedulesQuery, successEmptyHandler]]);
+
+ await waitForPromises();
+
+ expect(findEmptyState().exists()).toBe(false);
+ });
+ });
});
});
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
index e488a36f3dc..8f0e9fca379 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
@@ -1,4 +1,4 @@
-import { GlTableLite } from '@gitlab/ui';
+import { GlTable } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import PipelineSchedulesTable from '~/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue';
import { mockPipelineScheduleNodes, mockPipelineScheduleCurrentUser } from '../../mock_data';
@@ -19,7 +19,7 @@ describe('Pipeline schedules table', () => {
});
};
- const findTable = () => wrapper.findComponent(GlTableLite);
+ const findTable = () => wrapper.findComponent(GlTable);
const findScheduleDescription = () => wrapper.findByTestId('pipeline-schedule-description');
beforeEach(() => {
diff --git a/spec/frontend/ci/pipeline_schedules/mock_data.js b/spec/frontend/ci/pipeline_schedules/mock_data.js
index 0a4f233f199..8d4e0f1bea6 100644
--- a/spec/frontend/ci/pipeline_schedules/mock_data.js
+++ b/spec/frontend/ci/pipeline_schedules/mock_data.js
@@ -35,6 +35,19 @@ export const mockPipelineScheduleAsGuestNodes = guestNodes;
export const mockTakeOwnershipNodes = takeOwnershipNodes;
export const mockSinglePipelineScheduleNode = mockGetSinglePipelineScheduleGraphQLResponse;
+export const mockSinglePipelineScheduleNodeNoVars = {
+ data: {
+ currentUser: mockGetPipelineSchedulesGraphQLResponse.data.currentUser,
+ project: {
+ id: mockGetPipelineSchedulesGraphQLResponse.data.project.id,
+ pipelineSchedules: {
+ count: 1,
+ nodes: [mockGetPipelineSchedulesGraphQLResponse.data.project.pipelineSchedules.nodes[1]],
+ },
+ },
+ },
+};
+
export const emptyPipelineSchedulesResponse = {
data: {
currentUser: {
diff --git a/spec/frontend/ci/runner/admin_runners/provide_spec.js b/spec/frontend/ci/runner/admin_runners/provide_spec.js
new file mode 100644
index 00000000000..b24ddabbb66
--- /dev/null
+++ b/spec/frontend/ci/runner/admin_runners/provide_spec.js
@@ -0,0 +1,34 @@
+import { provide } from '~/ci/runner/admin_runners/provide';
+
+import {
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ runnerInstallHelpPage,
+} from 'jest/ci/runner/mock_data';
+
+const mockDataset = {
+ runnerInstallHelpPage,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+};
+
+describe('admin runners provide', () => {
+ it('returns provide values', () => {
+ expect(provide(mockDataset)).toMatchObject({
+ runnerInstallHelpPage,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ });
+ });
+
+ it('returns only provide values', () => {
+ const dataset = {
+ ...mockDataset,
+ extraEntry: 'ANOTHER_ENTRY',
+ };
+
+ expect(provide(dataset)).not.toMatchObject({
+ extraEntry: 'ANOTHER_ENTRY',
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
index e4373d1c198..3fb845b186a 100644
--- a/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
@@ -168,9 +168,8 @@ describe('RegistrationDropdown', () => {
expect(findTokenDropdownItem().exists()).toBe(true);
});
- it('Displays masked value by default', () => {
+ it('Displays masked value as password input by default', () => {
const mockToken = '0123456789';
- const maskToken = '**********';
createComponent(
{
@@ -179,7 +178,7 @@ describe('RegistrationDropdown', () => {
mountExtended,
);
- expect(findRegistrationTokenInput().element.value).toBe(maskToken);
+ expect(findRegistrationTokenInput().element.type).toBe('password');
});
});
diff --git a/spec/frontend/ci/runner/components/registration/registration_token_spec.js b/spec/frontend/ci/runner/components/registration/registration_token_spec.js
index fd3896d5500..eccfe43b47f 100644
--- a/spec/frontend/ci/runner/components/registration/registration_token_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_token_spec.js
@@ -38,10 +38,15 @@ describe('RegistrationToken', () => {
);
});
+ it('Renders readonly input', () => {
+ createComponent();
+
+ expect(findInputCopyToggleVisibility().props('readonly')).toBe(true);
+ });
+
// Component integration test to ensure secure masking
- it('Displays masked value by default', () => {
+ it('Displays masked value as password input by default', () => {
const mockToken = '0123456789';
- const maskToken = '**********';
createComponent({
props: {
@@ -50,7 +55,7 @@ describe('RegistrationToken', () => {
mountFn: mountExtended,
});
- expect(wrapper.find('input').element.value).toBe(maskToken);
+ expect(wrapper.find('input').element.type).toBe('password');
});
describe('When the copy to clipboard button is clicked', () => {
diff --git a/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js b/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
index e9f2e888b9a..91d2a20ec8a 100644
--- a/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
+++ b/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
@@ -6,7 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import TagToken, { TAG_SUGGESTIONS_PATH } from '~/ci/runner/components/search_tokens/tag_token.vue';
+import TagToken from '~/ci/runner/components/search_tokens/tag_token.vue';
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
import { getRecentlyUsedSuggestions } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
@@ -45,6 +45,8 @@ const mockTagTokenConfig = {
operators: OPERATORS_IS,
};
+const mockTagSuggestionsPath = '/path/runners/tag_list';
+
describe('TagToken', () => {
let mock;
let wrapper;
@@ -59,7 +61,8 @@ describe('TagToken', () => {
},
provide: {
portalName: 'fake target',
- alignSuggestions: function fakeAlignSuggestions() {},
+ tagSuggestionsPath: mockTagSuggestionsPath,
+ alignSuggestions: function fakeAligxnSuggestions() {},
filteredSearchSuggestionListInstance: {
register: jest.fn(),
unregister: jest.fn(),
@@ -80,9 +83,9 @@ describe('TagToken', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
- mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(HTTP_STATUS_OK, mockTags);
+ mock.onGet(mockTagSuggestionsPath, { params: { search: '' } }).reply(HTTP_STATUS_OK, mockTags);
mock
- .onGet(TAG_SUGGESTIONS_PATH, { params: { search: mockSearchTerm } })
+ .onGet(mockTagSuggestionsPath, { params: { search: mockSearchTerm } })
.reply(HTTP_STATUS_OK, mockTagsFiltered);
getRecentlyUsedSuggestions.mockReturnValue([]);
@@ -163,7 +166,7 @@ describe('TagToken', () => {
describe('when suggestions cannot be loaded', () => {
beforeEach(async () => {
mock
- .onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } })
+ .onGet(mockTagSuggestionsPath, { params: { search: '' } })
.reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
createComponent();
diff --git a/spec/frontend/ci/runner/mock_data.js b/spec/frontend/ci/runner/mock_data.js
index d72f93ad574..b8eb9f0ba1b 100644
--- a/spec/frontend/ci/runner/mock_data.js
+++ b/spec/frontend/ci/runner/mock_data.js
@@ -104,7 +104,7 @@ export const mockSearchExamples = [
},
},
{
- name: 'a two terms text search',
+ name: 'a two words text search',
urlQuery: '?search=something+else',
search: {
runnerType: null,
@@ -112,11 +112,7 @@ export const mockSearchExamples = [
filters: [
{
type: FILTERED_SEARCH_TERM,
- value: { data: 'something' },
- },
- {
- type: FILTERED_SEARCH_TERM,
- value: { data: 'else' },
+ value: { data: 'something else' },
},
],
pagination: {},
@@ -323,6 +319,7 @@ export const mockRegistrationToken = 'MOCK_REGISTRATION_TOKEN';
export const mockAuthenticationToken = 'MOCK_AUTHENTICATION_TOKEN';
export const newRunnerPath = '/runners/new';
+export const runnerInstallHelpPage = 'https://docs.example.com/runner/install/';
export {
allRunnersData,
diff --git a/spec/frontend/ci/runner/runner_search_utils_spec.js b/spec/frontend/ci/runner/runner_search_utils_spec.js
index 9a4a6139198..0623d2a3348 100644
--- a/spec/frontend/ci/runner/runner_search_utils_spec.js
+++ b/spec/frontend/ci/runner/runner_search_utils_spec.js
@@ -50,8 +50,7 @@ describe('search_params.js', () => {
it('When search params appear as array, they are concatenated', () => {
expect(fromUrlQueryToSearch('?search[]=my&search[]=text').filters).toEqual([
- { type: FILTERED_SEARCH_TERM, value: { data: 'my' } },
- { type: FILTERED_SEARCH_TERM, value: { data: 'text' } },
+ { type: FILTERED_SEARCH_TERM, value: { data: 'my text' } },
]);
});
});