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/jobs/components')
-rw-r--r--spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js71
-rw-r--r--spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js58
-rw-r--r--spec/frontend/jobs/components/filtered_search/utils_spec.js19
-rw-r--r--spec/frontend/jobs/components/job/artifacts_block_spec.js193
-rw-r--r--spec/frontend/jobs/components/job/commit_block_spec.js66
-rw-r--r--spec/frontend/jobs/components/job/empty_state_spec.js140
-rw-r--r--spec/frontend/jobs/components/job/environments_block_spec.js260
-rw-r--r--spec/frontend/jobs/components/job/erased_block_spec.js59
-rw-r--r--spec/frontend/jobs/components/job/job_app_spec.js343
-rw-r--r--spec/frontend/jobs/components/job/job_container_item_spec.js87
-rw-r--r--spec/frontend/jobs/components/job/job_log_controllers_spec.js323
-rw-r--r--spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js67
-rw-r--r--spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js133
-rw-r--r--spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js64
-rw-r--r--spec/frontend/jobs/components/job/jobs_container_spec.js143
-rw-r--r--spec/frontend/jobs/components/job/manual_variables_form_spec.js364
-rw-r--r--spec/frontend/jobs/components/job/mock_data.js123
-rw-r--r--spec/frontend/jobs/components/job/sidebar_detail_row_spec.js68
-rw-r--r--spec/frontend/jobs/components/job/sidebar_header_spec.js87
-rw-r--r--spec/frontend/jobs/components/job/sidebar_spec.js216
-rw-r--r--spec/frontend/jobs/components/job/stages_dropdown_spec.js191
-rw-r--r--spec/frontend/jobs/components/job/stuck_block_spec.js94
-rw-r--r--spec/frontend/jobs/components/job/trigger_block_spec.js81
-rw-r--r--spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js37
-rw-r--r--spec/frontend/jobs/components/log/collapsible_section_spec.js71
-rw-r--r--spec/frontend/jobs/components/log/duration_badge_spec.js26
-rw-r--r--spec/frontend/jobs/components/log/line_header_spec.js119
-rw-r--r--spec/frontend/jobs/components/log/line_number_spec.js35
-rw-r--r--spec/frontend/jobs/components/log/line_spec.js267
-rw-r--r--spec/frontend/jobs/components/log/log_spec.js135
-rw-r--r--spec/frontend/jobs/components/log/mock_data.js218
-rw-r--r--spec/frontend/jobs/components/table/cells/actions_cell_spec.js240
-rw-r--r--spec/frontend/jobs/components/table/cells/duration_cell_spec.js77
-rw-r--r--spec/frontend/jobs/components/table/cells/job_cell_spec.js142
-rw-r--r--spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js78
-rw-r--r--spec/frontend/jobs/components/table/graphql/cache_config_spec.js106
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js338
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js37
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_spec.js98
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_tabs_spec.js81
40 files changed, 0 insertions, 5355 deletions
diff --git a/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js b/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
deleted file mode 100644
index 5ecddc7efd6..00000000000
--- a/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { GlFilteredSearch } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import {
- OPERATORS_IS,
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
-import { mockFailedSearchToken } from '../../mock_data';
-
-describe('Jobs filtered search', () => {
- let wrapper;
-
- const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
- const getSearchToken = (type) =>
- findFilteredSearch()
- .props('availableTokens')
- .find((token) => token.type === type);
-
- const findStatusToken = () => getSearchToken('status');
-
- const createComponent = (props) => {
- wrapper = shallowMount(JobsFilteredSearch, {
- propsData: {
- ...props,
- },
- });
- };
-
- it('displays filtered search', () => {
- createComponent();
-
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- it('displays status token', () => {
- createComponent();
-
- expect(findStatusToken()).toMatchObject({
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- operators: OPERATORS_IS,
- });
- });
-
- it('emits filter token to parent component', () => {
- createComponent();
-
- findFilteredSearch().vm.$emit('submit', mockFailedSearchToken);
-
- expect(wrapper.emitted('filterJobsBySearch')).toEqual([[mockFailedSearchToken]]);
- });
-
- it('filtered search value is empty array when no query string is passed', () => {
- createComponent();
-
- expect(findFilteredSearch().props('value')).toEqual([]);
- });
-
- it('filtered search returns correct data shape when passed query string', () => {
- const value = 'SUCCESS';
-
- createComponent({ queryString: { statuses: value } });
-
- expect(findFilteredSearch().props('value')).toEqual([
- { type: TOKEN_TYPE_STATUS, value: { data: value, operator: '=' } },
- ]);
- });
-});
diff --git a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js b/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js
deleted file mode 100644
index 6755b854f01..00000000000
--- a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { stubComponent } from 'helpers/stub_component';
-import JobStatusToken from '~/jobs/components/filtered_search/tokens/job_status_token.vue';
-import {
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-
-describe('Job Status Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findAllGlIcons = () => wrapper.findAllComponents(GlIcon);
-
- const defaultProps = {
- config: {
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = () => {
- wrapper = shallowMount(JobStatusToken, {
- propsData: {
- ...defaultProps,
- },
- stubs: {
- GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
- template: `<div><slot name="suggestions"></slot></div>`,
- }),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- it('renders all job statuses available', () => {
- const expectedLength = 11;
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(expectedLength);
- expect(findAllGlIcons()).toHaveLength(expectedLength);
- });
-});
diff --git a/spec/frontend/jobs/components/filtered_search/utils_spec.js b/spec/frontend/jobs/components/filtered_search/utils_spec.js
deleted file mode 100644
index 8440ab42b86..00000000000
--- a/spec/frontend/jobs/components/filtered_search/utils_spec.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { validateQueryString } from '~/jobs/components/filtered_search/utils';
-
-describe('Filtered search utils', () => {
- describe('validateQueryString', () => {
- it.each`
- queryStringObject | expected
- ${{ statuses: 'SUCCESS' }} | ${{ statuses: 'SUCCESS' }}
- ${{ statuses: 'failed' }} | ${{ statuses: 'FAILED' }}
- ${{ wrong: 'SUCCESS' }} | ${null}
- ${{ statuses: 'wrong' }} | ${null}
- ${{ wrong: 'wrong' }} | ${null}
- `(
- 'when provided $queryStringObject, the expected result is $expected',
- ({ queryStringObject, expected }) => {
- expect(validateQueryString(queryStringObject)).toEqual(expected);
- },
- );
- });
-});
diff --git a/spec/frontend/jobs/components/job/artifacts_block_spec.js b/spec/frontend/jobs/components/job/artifacts_block_spec.js
deleted file mode 100644
index f9e52a5ae43..00000000000
--- a/spec/frontend/jobs/components/job/artifacts_block_spec.js
+++ /dev/null
@@ -1,193 +0,0 @@
-import { GlPopover } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { trimText } from 'helpers/text_helper';
-import ArtifactsBlock from '~/jobs/components/job/sidebar/artifacts_block.vue';
-import { getTimeago } from '~/lib/utils/datetime_utility';
-
-describe('Artifacts block', () => {
- let wrapper;
-
- const createWrapper = (propsData) =>
- mountExtended(ArtifactsBlock, {
- propsData: {
- helpUrl: 'help-url',
- ...propsData,
- },
- });
-
- const findArtifactRemoveElt = () => wrapper.findByTestId('artifacts-remove-timeline');
- const findJobLockedElt = () => wrapper.findByTestId('job-locked-message');
- const findKeepBtn = () => wrapper.findByTestId('keep-artifacts');
- const findDownloadBtn = () => wrapper.findByTestId('download-artifacts');
- const findBrowseBtn = () => wrapper.findByTestId('browse-artifacts');
- const findArtifactsHelpLink = () => wrapper.findByTestId('artifacts-help-link');
- const findPopover = () => wrapper.findComponent(GlPopover);
-
- const expireAt = '2018-08-14T09:38:49.157Z';
- const timeago = getTimeago();
- const formattedDate = timeago.format(expireAt);
- const lockedText =
- 'These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.';
-
- const expiredArtifact = {
- expire_at: expireAt,
- expired: true,
- locked: false,
- };
-
- const nonExpiredArtifact = {
- download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
- browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
- keep_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/keep',
- expire_at: expireAt,
- expired: false,
- locked: false,
- };
-
- const lockedExpiredArtifact = {
- ...expiredArtifact,
- download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
- browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
- expired: true,
- locked: true,
- };
-
- const lockedNonExpiredArtifact = {
- ...nonExpiredArtifact,
- keep_path: undefined,
- locked: true,
- };
-
- describe('with expired artifacts that are not locked', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: expiredArtifact,
- });
- });
-
- it('renders expired artifact date and info', () => {
- expect(trimText(findArtifactRemoveElt().text())).toBe(
- `The artifacts were removed ${formattedDate}`,
- );
-
- expect(
- findArtifactRemoveElt()
- .find('[data-testid="artifact-expired-help-link"]')
- .attributes('href'),
- ).toBe('help-url');
- });
-
- it('does not show the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('does not show the download button', () => {
- expect(findDownloadBtn().exists()).toBe(false);
- });
-
- it('does not show the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(false);
- });
- });
-
- describe('with artifacts that will expire', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: nonExpiredArtifact,
- });
- });
-
- it('renders will expire artifact date and info', () => {
- expect(trimText(findArtifactRemoveElt().text())).toBe(
- `The artifacts will be removed ${formattedDate}`,
- );
-
- expect(
- findArtifactRemoveElt()
- .find('[data-testid="artifact-expired-help-link"]')
- .attributes('href'),
- ).toBe('help-url');
- });
-
- it('renders the keep button', () => {
- expect(findKeepBtn().exists()).toBe(true);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('with expired locked artifacts', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedExpiredArtifact,
- });
- });
-
- it('renders the information that the artefacts are locked', () => {
- expect(findArtifactRemoveElt().exists()).toBe(false);
- expect(trimText(findJobLockedElt().text())).toBe(lockedText);
- });
-
- it('does not render the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('with non expired locked artifacts', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedNonExpiredArtifact,
- });
- });
-
- it('renders the information that the artefacts are locked', () => {
- expect(findArtifactRemoveElt().exists()).toBe(false);
- expect(trimText(findJobLockedElt().text())).toBe(lockedText);
- });
-
- it('does not render the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('artifacts help text', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedNonExpiredArtifact,
- });
- });
-
- it('displays help text', () => {
- const expectedHelpText =
- 'Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.';
-
- expect(findPopover().text()).toBe(expectedHelpText);
- });
-
- it('links to artifacts help page', () => {
- expect(findArtifactsHelpLink().attributes('href')).toBe('/help/ci/jobs/job_artifacts');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/commit_block_spec.js b/spec/frontend/jobs/components/job/commit_block_spec.js
deleted file mode 100644
index 1c28b5079d7..00000000000
--- a/spec/frontend/jobs/components/job/commit_block_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import CommitBlock from '~/jobs/components/job/sidebar/commit_block.vue';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-
-describe('Commit block', () => {
- let wrapper;
-
- const commit = {
- short_id: '1f0fb84f',
- id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
- commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
- title: 'Update README.md',
- };
-
- const mergeRequest = {
- iid: '!21244',
- path: 'merge_requests/21244',
- };
-
- const findCommitSha = () => wrapper.findByTestId('commit-sha');
- const findLinkSha = () => wrapper.findByTestId('link-commit');
-
- const mountComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(CommitBlock, {
- propsData: {
- commit,
- ...props,
- },
- }),
- );
- };
-
- describe('without merge request', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders pipeline short sha link', () => {
- expect(findCommitSha().attributes('href')).toBe(commit.commit_path);
- expect(findCommitSha().text()).toBe(commit.short_id);
- });
-
- it('renders clipboard button', () => {
- expect(wrapper.findComponent(ClipboardButton).attributes('text')).toBe(commit.id);
- });
-
- it('renders git commit title', () => {
- expect(wrapper.text()).toContain(commit.title);
- });
-
- it('does not render merge request', () => {
- expect(findLinkSha().exists()).toBe(false);
- });
- });
-
- describe('with merge request', () => {
- it('renders merge request link and reference', () => {
- mountComponent({ mergeRequest });
-
- expect(findLinkSha().attributes('href')).toBe(mergeRequest.path);
- expect(findLinkSha().text()).toBe(`!${mergeRequest.iid}`);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/empty_state_spec.js b/spec/frontend/jobs/components/job/empty_state_spec.js
deleted file mode 100644
index 970c2591795..00000000000
--- a/spec/frontend/jobs/components/job/empty_state_spec.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import EmptyState from '~/jobs/components/job/empty_state.vue';
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-import { mockFullPath, mockId } from './mock_data';
-
-describe('Empty State', () => {
- let wrapper;
-
- const defaultProps = {
- illustrationPath: 'illustrations/pending_job_empty.svg',
- illustrationSizeClass: 'svg-430',
- jobId: mockId,
- title: 'This job has not started yet',
- playable: false,
- isRetryable: true,
- };
-
- const createWrapper = (props) => {
- wrapper = shallowMountExtended(EmptyState, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- projectPath: mockFullPath,
- },
- });
- };
-
- const content = 'This job is in pending state and is waiting to be picked by a runner';
-
- const findEmptyStateImage = () => wrapper.find('img');
- const findTitle = () => wrapper.findByTestId('job-empty-state-title');
- const findContent = () => wrapper.findByTestId('job-empty-state-content');
- const findAction = () => wrapper.findByTestId('job-empty-state-action');
- const findManualVarsForm = () => wrapper.findComponent(ManualVariablesForm);
-
- describe('renders image and title', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders empty state image', () => {
- expect(findEmptyStateImage().exists()).toBe(true);
- });
-
- it('renders provided title', () => {
- expect(findTitle().text().trim()).toBe(defaultProps.title);
- });
- });
-
- describe('with content', () => {
- beforeEach(() => {
- createWrapper({ content });
- });
-
- it('renders content', () => {
- expect(findContent().text().trim()).toBe(content);
- });
- });
-
- describe('without content', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('does not render content', () => {
- expect(findContent().exists()).toBe(false);
- });
- });
-
- describe('with action', () => {
- beforeEach(() => {
- createWrapper({
- action: {
- path: 'runner',
- button_title: 'Check runner',
- method: 'post',
- },
- });
- });
-
- it('renders action', () => {
- expect(findAction().attributes('href')).toBe('runner');
- });
- });
-
- describe('without action', () => {
- beforeEach(() => {
- createWrapper({
- action: null,
- });
- });
-
- it('does not render action', () => {
- expect(findAction().exists()).toBe(false);
- });
-
- it('does not render manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(false);
- });
- });
-
- describe('with playable action and not scheduled job', () => {
- beforeEach(() => {
- createWrapper({
- content,
- playable: true,
- scheduled: false,
- action: {
- path: 'runner',
- button_title: 'Check runner',
- method: 'post',
- },
- });
- });
-
- it('renders manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(true);
- });
-
- it('does not render the empty state action', () => {
- expect(findAction().exists()).toBe(false);
- });
- });
-
- describe('with playable action and scheduled job', () => {
- beforeEach(() => {
- createWrapper({
- playable: true,
- scheduled: true,
- content,
- });
- });
-
- it('does not render manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/environments_block_spec.js b/spec/frontend/jobs/components/job/environments_block_spec.js
deleted file mode 100644
index ab36f79ea5e..00000000000
--- a/spec/frontend/jobs/components/job/environments_block_spec.js
+++ /dev/null
@@ -1,260 +0,0 @@
-import { mount } from '@vue/test-utils';
-import EnvironmentsBlock from '~/jobs/components/job/environments_block.vue';
-
-const TEST_CLUSTER_NAME = 'test_cluster';
-const TEST_CLUSTER_PATH = 'path/to/test_cluster';
-const TEST_KUBERNETES_NAMESPACE = 'this-is-a-kubernetes-namespace';
-
-describe('Environments block', () => {
- let wrapper;
-
- const status = {
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- };
-
- const environment = {
- environment_path: '/environment',
- name: 'environment',
- };
-
- const lastDeployment = { iid: 'deployment', deployable: { build_path: 'bar' } };
-
- const createEnvironmentWithLastDeployment = () => ({
- ...environment,
- last_deployment: { ...lastDeployment },
- });
-
- const createDeploymentWithCluster = () => ({ name: TEST_CLUSTER_NAME, path: TEST_CLUSTER_PATH });
-
- const createDeploymentWithClusterAndKubernetesNamespace = () => ({
- name: TEST_CLUSTER_NAME,
- path: TEST_CLUSTER_PATH,
- kubernetes_namespace: TEST_KUBERNETES_NAMESPACE,
- });
-
- const createComponent = (deploymentStatus = {}, deploymentCluster = {}) => {
- wrapper = mount(EnvironmentsBlock, {
- propsData: {
- deploymentStatus,
- deploymentCluster,
- iconStatus: status,
- },
- });
- };
-
- const findText = () => wrapper.findComponent(EnvironmentsBlock).text();
- const findJobDeploymentLink = () => wrapper.find('[data-testid="job-deployment-link"]');
- const findEnvironmentLink = () => wrapper.find('[data-testid="job-environment-link"]');
- const findClusterLink = () => wrapper.find('[data-testid="job-cluster-link"]');
-
- describe('with last deployment', () => {
- it('renders info for most recent deployment', () => {
- createComponent({
- status: 'last',
- environment,
- });
-
- expect(findText()).toBe('This job is deployed to environment.');
- });
-
- describe('when there is a cluster', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
- });
-
- describe('when there is a kubernetes namespace', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithClusterAndKubernetesNamespace(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}.`,
- );
- });
- });
- });
- });
-
- describe('with out of date deployment', () => {
- describe('with last deployment', () => {
- it('renders info for out date and most recent', () => {
- createComponent({
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- });
-
- expect(findText()).toBe(
- 'This job is an out-of-date deployment to environment. View the most recent deployment.',
- );
-
- expect(findJobDeploymentLink().attributes('href')).toBe('bar');
- });
-
- describe('when there is a cluster', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME}. View the most recent deployment.`,
- );
- });
-
- describe('when there is a kubernetes namespace', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithClusterAndKubernetesNamespace(),
- );
-
- expect(findText()).toBe(
- `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}. View the most recent deployment.`,
- );
- });
- });
- });
- });
-
- describe('without last deployment', () => {
- it('renders info about out of date deployment', () => {
- createComponent({
- status: 'out_of_date',
- environment,
- });
-
- expect(findText()).toBe('This job is an out-of-date deployment to environment.');
- });
- });
- });
-
- describe('with failed deployment', () => {
- it('renders info about failed deployment', () => {
- createComponent({
- status: 'failed',
- environment,
- });
-
- expect(findText()).toBe('The deployment of this job to environment did not succeed.');
- });
- });
-
- describe('creating deployment', () => {
- describe('with last deployment', () => {
- it('renders info about creating deployment and overriding latest deployment', () => {
- createComponent({
- status: 'creating',
- environment: createEnvironmentWithLastDeployment(),
- });
-
- expect(findText()).toBe(
- 'This job is creating a deployment to environment. This will overwrite the latest deployment.',
- );
-
- expect(findEnvironmentLink().attributes('href')).toBe(environment.environment_path);
-
- expect(findJobDeploymentLink().attributes('href')).toBe('bar');
-
- expect(findClusterLink().exists()).toBe(false);
- });
- });
-
- describe('without last deployment', () => {
- it('renders info about deployment being created', () => {
- createComponent({
- status: 'creating',
- environment,
- });
-
- expect(findText()).toBe('This job is creating a deployment to environment.');
- });
-
- describe('when there is a cluster', () => {
- it('inclues information about the cluster', () => {
- createComponent(
- {
- status: 'creating',
- environment,
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is creating a deployment to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
- });
- });
- });
-
- describe('without environment', () => {
- it('does not render environment link', () => {
- createComponent({
- status: 'creating',
- environment: null,
- });
-
- expect(findEnvironmentLink().exists()).toBe(false);
- });
- });
- });
-
- describe('with a cluster', () => {
- it('renders the cluster link', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
-
- expect(findClusterLink().attributes('href')).toBe(TEST_CLUSTER_PATH);
- });
-
- describe('when the cluster is missing the path', () => {
- it('renders the name without a link', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- { name: 'the-cluster' },
- );
-
- expect(findText()).toContain('using cluster the-cluster.');
-
- expect(findClusterLink().exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/erased_block_spec.js b/spec/frontend/jobs/components/job/erased_block_spec.js
deleted file mode 100644
index aeab676fc7e..00000000000
--- a/spec/frontend/jobs/components/job/erased_block_spec.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import ErasedBlock from '~/jobs/components/job/erased_block.vue';
-import { getTimeago } from '~/lib/utils/datetime_utility';
-
-describe('Erased block', () => {
- let wrapper;
-
- const erasedAt = '2016-11-07T11:11:16.525Z';
- const timeago = getTimeago();
- const formattedDate = timeago.format(erasedAt);
-
- const findLink = () => wrapper.findComponent(GlLink);
-
- const createComponent = (props) => {
- wrapper = mount(ErasedBlock, {
- propsData: props,
- });
- };
-
- describe('with job erased by user', () => {
- beforeEach(() => {
- createComponent({
- user: {
- username: 'root',
- web_url: 'gitlab.com/root',
- },
- erasedAt,
- });
- });
-
- it('renders username and link', () => {
- expect(findLink().attributes('href')).toEqual('gitlab.com/root');
-
- expect(wrapper.text().trim()).toContain('Job has been erased by');
- expect(wrapper.text().trim()).toContain('root');
- });
-
- it('renders erasedAt', () => {
- expect(wrapper.text().trim()).toContain(formattedDate);
- });
- });
-
- describe('with erased job', () => {
- beforeEach(() => {
- createComponent({
- erasedAt,
- });
- });
-
- it('renders username and link', () => {
- expect(wrapper.text().trim()).toContain('Job has been erased');
- });
-
- it('renders erasedAt', () => {
- expect(wrapper.text().trim()).toContain(formattedDate);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_app_spec.js b/spec/frontend/jobs/components/job/job_app_spec.js
deleted file mode 100644
index 8f5700ee22d..00000000000
--- a/spec/frontend/jobs/components/job/job_app_spec.js
+++ /dev/null
@@ -1,343 +0,0 @@
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { GlLoadingIcon } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import EmptyState from '~/jobs/components/job/empty_state.vue';
-import EnvironmentsBlock from '~/jobs/components/job/environments_block.vue';
-import ErasedBlock from '~/jobs/components/job/erased_block.vue';
-import JobApp from '~/jobs/components/job/job_app.vue';
-import JobLog from '~/jobs/components/log/log.vue';
-import JobLogTopBar from 'ee_else_ce/jobs/components/job/job_log_controllers.vue';
-import Sidebar from '~/jobs/components/job/sidebar/sidebar.vue';
-import StuckBlock from '~/jobs/components/job/stuck_block.vue';
-import UnmetPrerequisitesBlock from '~/jobs/components/job/unmet_prerequisites_block.vue';
-import createStore from '~/jobs/store';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { MANUAL_STATUS } from '~/jobs/constants';
-import job from '../../mock_data';
-import { mockPendingJobData } from './mock_data';
-
-describe('Job App', () => {
- Vue.use(Vuex);
-
- let store;
- let wrapper;
- let mock;
-
- const initSettings = {
- endpoint: `${TEST_HOST}jobs/123.json`,
- pagePath: `${TEST_HOST}jobs/123`,
- logState:
- 'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
- };
-
- const props = {
- artifactHelpUrl: 'help/artifact',
- deploymentHelpUrl: 'help/deployment',
- runnerSettingsUrl: 'settings/ci-cd/runners',
- terminalPath: 'jobs/123/terminal',
- projectPath: 'user-name/project-name',
- subscriptionsMoreMinutesUrl: 'https://customers.gitlab.com/buy_pipeline_minutes',
- };
-
- const createComponent = () => {
- wrapper = shallowMountExtended(JobApp, {
- propsData: { ...props },
- store,
- });
- };
-
- const setupAndMount = async ({ jobData = {}, jobLogData = {} } = {}) => {
- mock.onGet(initSettings.endpoint).replyOnce(HTTP_STATUS_OK, { ...job, ...jobData });
- mock.onGet(`${initSettings.pagePath}/trace.json`).reply(HTTP_STATUS_OK, jobLogData);
-
- const asyncInit = store.dispatch('init', initSettings);
-
- createComponent();
-
- await asyncInit;
- jest.runOnlyPendingTimers();
- await axios.waitForAll();
- await nextTick();
- };
-
- const findLoadingComponent = () => wrapper.findComponent(GlLoadingIcon);
- const findSidebar = () => wrapper.findComponent(Sidebar);
- const findStuckBlockComponent = () => wrapper.findComponent(StuckBlock);
- const findFailedJobComponent = () => wrapper.findComponent(UnmetPrerequisitesBlock);
- const findEnvironmentsBlockComponent = () => wrapper.findComponent(EnvironmentsBlock);
- const findErasedBlock = () => wrapper.findComponent(ErasedBlock);
- const findEmptyState = () => wrapper.findComponent(EmptyState);
- const findJobLog = () => wrapper.findComponent(JobLog);
- const findJobLogTopBar = () => wrapper.findComponent(JobLogTopBar);
-
- const findJobContent = () => wrapper.findByTestId('job-content');
- const findArchivedJob = () => wrapper.findByTestId('archived-job');
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- store = createStore();
- });
-
- afterEach(() => {
- mock.restore();
- // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
- wrapper.destroy();
- });
-
- describe('while loading', () => {
- beforeEach(() => {
- store.state.isLoading = true;
- createComponent();
- });
-
- it('renders loading icon', () => {
- expect(findLoadingComponent().exists()).toBe(true);
- expect(findSidebar().exists()).toBe(false);
- expect(findJobContent().exists()).toBe(false);
- });
- });
-
- describe('with successful request', () => {
- describe('Header section', () => {
- describe('job callout message', () => {
- it('should not render the reason when reason is absent', () =>
- setupAndMount().then(() => {
- expect(wrapper.vm.shouldRenderCalloutMessage).toBe(false);
- }));
-
- it('should render the reason when reason is present', () =>
- setupAndMount({
- jobData: {
- callout_message: 'There is an unkown failure, please try again',
- },
- }).then(() => {
- expect(wrapper.vm.shouldRenderCalloutMessage).toBe(true);
- }));
- });
- });
-
- describe('stuck block', () => {
- describe('without active runners available', () => {
- it('renders stuck block when there are no runners', () =>
- setupAndMount({
- jobData: {
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- },
- stuck: true,
- runners: {
- available: false,
- online: false,
- },
- tags: [],
- },
- }).then(() => {
- expect(findStuckBlockComponent().exists()).toBe(true);
- }));
- });
-
- it('does not render stuck block when there are runners', () =>
- setupAndMount({
- jobData: {
- runners: { available: true },
- },
- }).then(() => {
- expect(findStuckBlockComponent().exists()).toBe(false);
- }));
- });
-
- describe('unmet prerequisites block', () => {
- it('renders unmet prerequisites block when there is an unmet prerequisites failure', () =>
- setupAndMount({
- jobData: {
- status: {
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- details_path: 'path',
- illustration: {
- content: 'Retry this job in order to create the necessary resources.',
- image: 'path',
- size: 'svg-430',
- title: 'Failed to create resources',
- },
- },
- failure_reason: 'unmet_prerequisites',
- has_trace: false,
- runners: {
- available: true,
- },
- tags: [],
- },
- }).then(() => {
- expect(findFailedJobComponent().exists()).toBe(true);
- }));
- });
-
- describe('environments block', () => {
- it('renders environment block when job has environment', () =>
- setupAndMount({
- jobData: {
- deployment_status: {
- environment: {
- environment_path: '/path',
- name: 'foo',
- },
- },
- },
- }).then(() => {
- expect(findEnvironmentsBlockComponent().exists()).toBe(true);
- }));
-
- it('does not render environment block when job has environment', () =>
- setupAndMount().then(() => {
- expect(findEnvironmentsBlockComponent().exists()).toBe(false);
- }));
- });
-
- describe('erased block', () => {
- it('renders erased block when `erased` is true', () =>
- setupAndMount({
- jobData: {
- erased_by: {
- username: 'root',
- web_url: 'gitlab.com/root',
- },
- erased_at: '2016-11-07T11:11:16.525Z',
- },
- }).then(() => {
- expect(findErasedBlock().exists()).toBe(true);
- }));
-
- it('does not render erased block when `erased` is false', () =>
- setupAndMount({
- jobData: {
- erased_at: null,
- },
- }).then(() => {
- expect(findErasedBlock().exists()).toBe(false);
- }));
- });
-
- describe('empty states block', () => {
- it('renders empty state when job does not have log and is not running', () =>
- setupAndMount({
- jobData: {
- has_trace: false,
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- illustration: {
- image: 'path',
- size: '340',
- title: 'Empty State',
- content: 'This is an empty state',
- },
- action: {
- button_title: 'Retry job',
- method: 'post',
- path: '/path',
- },
- },
- },
- }).then(() => {
- expect(findEmptyState().exists()).toBe(true);
- }));
-
- it('does not render empty state when job does not have log but it is running', () =>
- setupAndMount({
- jobData: {
- has_trace: false,
- status: {
- group: 'running',
- icon: 'status_running',
- label: 'running',
- text: 'running',
- details_path: 'path',
- },
- },
- }).then(() => {
- expect(findEmptyState().exists()).toBe(false);
- }));
-
- it('does not render empty state when job has log but it is not running', () =>
- setupAndMount({ jobData: { has_trace: true } }).then(() => {
- expect(findEmptyState().exists()).toBe(false);
- }));
- });
-
- describe('sidebar', () => {
- it('renders sidebar', async () => {
- await setupAndMount();
-
- expect(findSidebar().exists()).toBe(true);
- });
- });
- });
-
- describe('archived job', () => {
- beforeEach(() => setupAndMount({ jobData: { archived: true } }));
-
- it('renders warning about job being archived', () => {
- expect(findArchivedJob().exists()).toBe(true);
- });
- });
-
- describe('non-archived job', () => {
- beforeEach(() => setupAndMount());
-
- it('does not warning about job being archived', () => {
- expect(findArchivedJob().exists()).toBe(false);
- });
- });
-
- describe('job log', () => {
- beforeEach(() => setupAndMount());
-
- it('should render job log header', () => {
- expect(findJobLogTopBar().exists()).toBe(true);
- });
-
- it('should render job log', () => {
- expect(findJobLog().exists()).toBe(true);
- });
- });
-
- describe('job log polling', () => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
- });
-
- it('should poll job log by default', async () => {
- await setupAndMount({
- jobData: mockPendingJobData,
- });
-
- expect(store.dispatch).toHaveBeenCalledWith('fetchJobLog');
- });
-
- it('should NOT poll job log for manual variables form empty state', async () => {
- const manualPendingJobData = mockPendingJobData;
- manualPendingJobData.status.group = MANUAL_STATUS;
-
- await setupAndMount({
- jobData: manualPendingJobData,
- });
-
- expect(store.dispatch).not.toHaveBeenCalledWith('fetchJobLog');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_container_item_spec.js b/spec/frontend/jobs/components/job/job_container_item_spec.js
deleted file mode 100644
index 39782130d38..00000000000
--- a/spec/frontend/jobs/components/job/job_container_item_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { GlIcon, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import delayedJobFixture from 'test_fixtures/jobs/delayed.json';
-import JobContainerItem from '~/jobs/components/job/sidebar/job_container_item.vue';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import job from '../../mock_data';
-
-describe('JobContainerItem', () => {
- let wrapper;
-
- const findCiIcon = () => wrapper.findComponent(CiIcon);
- const findGlIcon = () => wrapper.findComponent(GlIcon);
-
- function createComponent(jobData = {}, props = { isActive: false, retried: false }) {
- wrapper = shallowMount(JobContainerItem, {
- propsData: {
- job: {
- ...jobData,
- retried: props.retried,
- },
- isActive: props.isActive,
- },
- });
- }
-
- describe('when a job is not active and not retried', () => {
- beforeEach(() => {
- createComponent(job);
- });
-
- it('displays a status icon', () => {
- expect(findCiIcon().props('status')).toBe(job.status);
- });
-
- it('displays the job name', () => {
- expect(wrapper.text()).toContain(job.name);
- });
-
- it('displays a link to the job', () => {
- const link = wrapper.findComponent(GlLink);
-
- expect(link.attributes('href')).toBe(job.status.details_path);
- });
- });
-
- describe('when a job is active', () => {
- beforeEach(() => {
- createComponent(job, { isActive: true });
- });
-
- it('displays an arrow sprite icon', () => {
- expect(findGlIcon().props('name')).toBe('arrow-right');
- });
- });
-
- describe('when a job is retried', () => {
- beforeEach(() => {
- createComponent(job, { isActive: false, retried: true });
- });
-
- it('displays a retry icon', () => {
- expect(findGlIcon().props('name')).toBe('retry');
- });
- });
-
- describe('for a delayed job', () => {
- beforeEach(() => {
- const remainingMilliseconds = 1337000;
- jest
- .spyOn(Date, 'now')
- .mockImplementation(
- () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingMilliseconds,
- );
-
- createComponent(delayedJobFixture);
- });
-
- it('displays remaining time in tooltip', async () => {
- await nextTick();
-
- const link = wrapper.findComponent(GlLink);
-
- expect(link.attributes('title')).toMatch('delayed job - delayed manual action (00:22:17)');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_log_controllers_spec.js b/spec/frontend/jobs/components/job/job_log_controllers_spec.js
deleted file mode 100644
index 7b6d58f63d1..00000000000
--- a/spec/frontend/jobs/components/job/job_log_controllers_spec.js
+++ /dev/null
@@ -1,323 +0,0 @@
-import { GlSearchBoxByClick } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import JobLogControllers from '~/jobs/components/job/job_log_controllers.vue';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import { backoffMockImplementation } from 'helpers/backoff_helper';
-import * as commonUtils from '~/lib/utils/common_utils';
-import { mockJobLog } from '../../mock_data';
-
-const mockToastShow = jest.fn();
-
-describe('Job log controllers', () => {
- let wrapper;
-
- beforeEach(() => {
- jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
- });
-
- afterEach(() => {
- commonUtils.backOff.mockReset();
- });
-
- const defaultProps = {
- rawPath: '/raw',
- size: 511952,
- isScrollTopDisabled: false,
- isScrollBottomDisabled: false,
- isScrollingDown: true,
- isJobLogSizeVisible: true,
- isComplete: true,
- jobLog: mockJobLog,
- };
-
- const createWrapper = (props, { jobLogJumpToFailures = false } = {}) => {
- wrapper = mount(JobLogControllers, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- glFeatures: {
- jobLogJumpToFailures,
- },
- },
- data() {
- return {
- searchTerm: '82',
- };
- },
- mocks: {
- $toast: {
- show: mockToastShow,
- },
- },
- });
- };
-
- const findTruncatedInfo = () => wrapper.find('[data-testid="log-truncated-info"]');
- const findRawLink = () => wrapper.find('[data-testid="raw-link"]');
- const findRawLinkController = () => wrapper.find('[data-testid="job-raw-link-controller"]');
- const findScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]');
- const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]');
- const findJobLogSearch = () => wrapper.findComponent(GlSearchBoxByClick);
- const findSearchHelp = () => wrapper.findComponent(HelpPopover);
- const findScrollFailure = () => wrapper.find('[data-testid="job-controller-scroll-to-failure"]');
-
- describe('Truncate information', () => {
- describe('with isJobLogSizeVisible', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders size information', () => {
- expect(findTruncatedInfo().text()).toMatch('499.95 KiB');
- });
-
- it('renders link to raw job log', () => {
- expect(findRawLink().attributes('href')).toBe(defaultProps.rawPath);
- });
- });
- });
-
- describe('links section', () => {
- describe('with raw job log path', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders raw job log link', () => {
- expect(findRawLinkController().attributes('href')).toBe(defaultProps.rawPath);
- });
- });
-
- describe('without raw job log path', () => {
- beforeEach(() => {
- createWrapper({
- rawPath: null,
- });
- });
-
- it('does not render raw job log link', () => {
- expect(findRawLinkController().exists()).toBe(false);
- });
- });
- });
-
- describe('scroll buttons', () => {
- describe('scroll top button', () => {
- describe('when user can scroll top', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: false,
- });
- });
-
- it('emits scrollJobLogTop event on click', async () => {
- await findScrollTop().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogTop).toHaveLength(1);
- });
- });
-
- describe('when user can not scroll top', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: true,
- isScrollBottomDisabled: false,
- isScrollingDown: false,
- });
- });
-
- it('renders disabled scroll top button', () => {
- expect(findScrollTop().attributes('disabled')).toBeDefined();
- });
-
- it('does not emit scrollJobLogTop event on click', async () => {
- await findScrollTop().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogTop).toBeUndefined();
- });
- });
- });
-
- describe('scroll bottom button', () => {
- describe('when user can scroll bottom', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('emits scrollJobLogBottom event on click', async () => {
- await findScrollBottom().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogBottom).toHaveLength(1);
- });
- });
-
- describe('when user can not scroll bottom', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: false,
- isScrollBottomDisabled: true,
- isScrollingDown: false,
- });
- });
-
- it('renders disabled scroll bottom button', () => {
- expect(findScrollBottom().attributes('disabled')).toEqual('disabled');
- });
-
- it('does not emit scrollJobLogBottom event on click', async () => {
- await findScrollBottom().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogBottom).toBeUndefined();
- });
- });
-
- describe('while isScrollingDown is true', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders animate class for the scroll down button', () => {
- expect(findScrollBottom().classes()).toContain('animate');
- });
- });
-
- describe('while isScrollingDown is false', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: true,
- isScrollBottomDisabled: false,
- isScrollingDown: false,
- });
- });
-
- it('does not render animate class for the scroll down button', () => {
- expect(findScrollBottom().classes()).not.toContain('animate');
- });
- });
- });
-
- describe('scroll to failure button', () => {
- describe('with feature flag disabled', () => {
- it('does not display button', () => {
- createWrapper();
-
- expect(findScrollFailure().exists()).toBe(false);
- });
- });
-
- describe('with red text failures on the page', () => {
- let firstFailure;
- let secondFailure;
-
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
-
- createWrapper({}, { jobLogJumpToFailures: true });
-
- firstFailure = document.createElement('div');
- firstFailure.className = 'term-fg-l-red';
- document.body.appendChild(firstFailure);
-
- secondFailure = document.createElement('div');
- secondFailure.className = 'term-fg-l-red';
- document.body.appendChild(secondFailure);
- });
-
- afterEach(() => {
- if (firstFailure) {
- firstFailure.remove();
- firstFailure = null;
- }
-
- if (secondFailure) {
- secondFailure.remove();
- secondFailure = null;
- }
- });
-
- it('is enabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(false);
- });
-
- it('scrolls to each failure', async () => {
- jest.spyOn(firstFailure, 'scrollIntoView');
-
- await findScrollFailure().trigger('click');
-
- expect(firstFailure.scrollIntoView).toHaveBeenCalled();
-
- await findScrollFailure().trigger('click');
-
- expect(secondFailure.scrollIntoView).toHaveBeenCalled();
-
- await findScrollFailure().trigger('click');
-
- expect(firstFailure.scrollIntoView).toHaveBeenCalled();
- });
- });
-
- describe('with no red text failures on the page', () => {
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce([]);
-
- createWrapper({}, { jobLogJumpToFailures: true });
- });
-
- it('is disabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(true);
- });
- });
-
- describe('when the job log is not complete', () => {
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
-
- createWrapper({ isComplete: false }, { jobLogJumpToFailures: true });
- });
-
- it('is enabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(false);
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- jest.spyOn(commonUtils, 'backOff').mockRejectedValueOnce();
-
- createWrapper({}, { jobLogJumpToFailures: true });
- });
-
- it('stays disabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(true);
- });
- });
- });
- });
-
- describe('Job log search', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('displays job log search', () => {
- expect(findJobLogSearch().exists()).toBe(true);
- expect(findSearchHelp().exists()).toBe(true);
- });
-
- it('emits search results', () => {
- const expectedSearchResults = [[[mockJobLog[6].lines[1], mockJobLog[6].lines[2]]]];
-
- findJobLogSearch().vm.$emit('submit');
-
- expect(wrapper.emitted('searchResults')).toEqual(expectedSearchResults);
- });
-
- it('clears search results', () => {
- findJobLogSearch().vm.$emit('clear');
-
- expect(wrapper.emitted('searchResults')).toEqual([[[]]]);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js b/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
deleted file mode 100644
index a44a13259aa..00000000000
--- a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { GlLink, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import JobRetryForwardDeploymentModal from '~/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue';
-import { JOB_RETRY_FORWARD_DEPLOYMENT_MODAL } from '~/jobs/constants';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Retry Forward Deployment Modal', () => {
- let store;
- let wrapper;
-
- const retryOutdatedJobDocsUrl = 'url-to-docs';
- const findLink = () => wrapper.findComponent(GlLink);
- const findModal = () => wrapper.findComponent(GlModal);
-
- const createWrapper = ({ props = {}, provide = {}, stubs = {} } = {}) => {
- store = createStore();
- wrapper = shallowMount(JobRetryForwardDeploymentModal, {
- propsData: {
- modalId: 'modal-id',
- href: job.retry_path,
- ...props,
- },
- provide,
- store,
- stubs,
- });
- };
-
- beforeEach(createWrapper);
-
- describe('Modal configuration', () => {
- it('should display the correct messages', () => {
- const modal = findModal();
- expect(modal.attributes('title')).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.title);
- expect(modal.text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.info);
- expect(modal.text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.areYouSure);
- });
- });
-
- describe('Modal docs help link', () => {
- it('should not display an info link when none is provided', () => {
- createWrapper();
-
- expect(findLink().exists()).toBe(false);
- });
-
- it('should display an info link when one is provided', () => {
- createWrapper({ provide: { retryOutdatedJobDocsUrl } });
-
- expect(findLink().attributes('href')).toBe(retryOutdatedJobDocsUrl);
- expect(findLink().text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.moreInfo);
- });
- });
-
- describe('Modal actions', () => {
- beforeEach(createWrapper);
-
- it('should correctly configure the primary action', () => {
- expect(findModal().props('actionPrimary').attributes).toMatchObject({
- 'data-method': 'post',
- href: job.retry_path,
- variant: 'danger',
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js b/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js
deleted file mode 100644
index c1028f3929d..00000000000
--- a/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import DetailRow from '~/jobs/components/job/sidebar/sidebar_detail_row.vue';
-import SidebarJobDetailsContainer from '~/jobs/components/job/sidebar/sidebar_job_details_container.vue';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Sidebar Details Container', () => {
- let store;
- let wrapper;
-
- const findJobTimeout = () => wrapper.findByTestId('job-timeout');
- const findJobTags = () => wrapper.findByTestId('job-tags');
- const findAllDetailsRow = () => wrapper.findAllComponents(DetailRow);
-
- const createWrapper = ({ props = {} } = {}) => {
- store = createStore();
- wrapper = extendedWrapper(
- shallowMount(SidebarJobDetailsContainer, {
- propsData: props,
- store,
- stubs: {
- DetailRow,
- },
- }),
- );
- };
-
- describe('when no details are available', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('should render an empty container', () => {
- expect(wrapper.html()).toBe('');
- });
-
- it.each(['duration', 'erased_at', 'finished_at', 'queued_at', 'runner', 'coverage'])(
- 'should not render %s details when missing',
- async (detail) => {
- await store.dispatch('receiveJobSuccess', { [detail]: undefined });
-
- expect(findAllDetailsRow()).toHaveLength(0);
- },
- );
- });
-
- describe('when some of the details are available', () => {
- beforeEach(createWrapper);
-
- it.each([
- ['duration', 'Elapsed time: 6 seconds'],
- ['erased_at', 'Erased: 3 weeks ago'],
- ['finished_at', 'Finished: 3 weeks ago'],
- ['queued_duration', 'Queued: 9 seconds'],
- ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'],
- ['coverage', 'Coverage: 20%'],
- ])('uses %s to render job-%s', async (detail, value) => {
- await store.dispatch('receiveJobSuccess', { [detail]: job[detail] });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow).toHaveLength(1);
- expect(detailsRow.at(0).text()).toBe(value);
- });
-
- it('only renders tags', async () => {
- const { tags } = job;
- await store.dispatch('receiveJobSuccess', { tags });
- const tagsComponent = findJobTags();
-
- expect(tagsComponent.text()).toBe('Tags: tag');
- });
- });
-
- describe('when all the info are available', () => {
- it('renders all the details components', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findAllDetailsRow()).toHaveLength(7);
- });
-
- describe('duration row', () => {
- it('renders all the details components', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findAllDetailsRow().at(0).text()).toBe('Duration: 6 seconds');
- });
- });
- });
-
- describe('timeout', () => {
- const {
- metadata: { timeout_human_readable, timeout_source },
- } = job;
-
- beforeEach(createWrapper);
-
- it('does not render if metadata is empty', async () => {
- const metadata = {};
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(wrapper.html()).toBe('');
- expect(detailsRow.exists()).toBe(false);
- });
-
- it('uses metadata to render timeout', async () => {
- const metadata = { timeout_human_readable };
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow).toHaveLength(1);
- expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s');
- });
-
- it('uses metadata to render timeout and the source', async () => {
- const metadata = { timeout_human_readable, timeout_source };
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s (from runner)');
- });
-
- it('should not render when no time is provided', async () => {
- const metadata = { timeout_source };
- await store.dispatch('receiveJobSuccess', { metadata });
-
- expect(findJobTimeout().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js b/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js
deleted file mode 100644
index 8a63bfdc3d6..00000000000
--- a/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import JobsSidebarRetryButton from '~/jobs/components/job/sidebar/job_sidebar_retry_button.vue';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Sidebar Retry Button', () => {
- let store;
- let wrapper;
-
- const forwardDeploymentFailure = 'forward_deployment_failure';
- const findRetryButton = () => wrapper.findByTestId('retry-job-button');
- const findRetryLink = () => wrapper.findByTestId('retry-job-link');
-
- const createWrapper = ({ props = {} } = {}) => {
- store = createStore();
- wrapper = shallowMountExtended(JobsSidebarRetryButton, {
- propsData: {
- href: job.retry_path,
- isManualJob: false,
- modalId: 'modal-id',
- ...props,
- },
- store,
- });
- };
-
- beforeEach(createWrapper);
-
- it.each([
- [null, false, true],
- ['unmet_prerequisites', false, true],
- [forwardDeploymentFailure, true, false],
- ])(
- 'when error is: %s, should render button: %s | should render link: %s',
- async (failureReason, buttonExists, linkExists) => {
- await store.dispatch('receiveJobSuccess', { ...job, failure_reason: failureReason });
-
- expect(findRetryButton().exists()).toBe(buttonExists);
- expect(findRetryLink().exists()).toBe(linkExists);
- },
- );
-
- describe('Button', () => {
- it('should have the correct configuration', async () => {
- await store.dispatch('receiveJobSuccess', { failure_reason: forwardDeploymentFailure });
-
- expect(findRetryButton().attributes()).toMatchObject({
- category: 'primary',
- variant: 'confirm',
- icon: 'retry',
- });
- });
- });
-
- describe('Link', () => {
- it('should have the correct configuration', () => {
- expect(findRetryLink().attributes()).toMatchObject({
- 'data-method': 'post',
- href: job.retry_path,
- icon: 'retry',
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/jobs_container_spec.js b/spec/frontend/jobs/components/job/jobs_container_spec.js
deleted file mode 100644
index 05660880751..00000000000
--- a/spec/frontend/jobs/components/job/jobs_container_spec.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsContainer from '~/jobs/components/job/sidebar/jobs_container.vue';
-
-describe('Jobs List block', () => {
- let wrapper;
-
- const retried = {
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 233432756,
- tooltip: 'build - passed',
- retried: true,
- };
-
- const active = {
- name: 'test',
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 2322756,
- tooltip: 'build - passed',
- active: true,
- };
-
- const job = {
- name: 'build',
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 232153,
- tooltip: 'build - passed',
- };
-
- const findAllJobs = () => wrapper.findAllComponents(GlLink);
- const findJob = () => findAllJobs().at(0);
-
- const findArrowIcon = () => wrapper.findByTestId('arrow-right-icon');
- const findRetryIcon = () => wrapper.findByTestId('retry-icon');
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- mount(JobsContainer, {
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- it('renders a list of jobs', () => {
- createComponent({
- jobs: [job, retried, active],
- jobId: 12313,
- });
-
- expect(findAllJobs()).toHaveLength(3);
- });
-
- it('renders the arrow right icon when job id matches `jobId`', () => {
- createComponent({
- jobs: [active],
- jobId: active.id,
- });
-
- expect(findArrowIcon().exists()).toBe(true);
- });
-
- it('does not render the arrow right icon when the job is not active', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findArrowIcon().exists()).toBe(false);
- });
-
- it('renders the job name when present', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findJob().text()).toBe(job.name);
- expect(findJob().text()).not.toContain(job.id.toString());
- });
-
- it('renders job id when job name is not available', () => {
- createComponent({
- jobs: [retried],
- jobId: active.id,
- });
-
- expect(findJob().text()).toBe(retried.id.toString());
- });
-
- it('links to the job page', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findJob().attributes('href')).toBe(job.status.details_path);
- });
-
- it('renders retry icon when job was retried', () => {
- createComponent({
- jobs: [retried],
- jobId: active.id,
- });
-
- expect(findRetryIcon().exists()).toBe(true);
- });
-
- it('does not render retry icon when job was not retried', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findRetryIcon().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/jobs/components/job/manual_variables_form_spec.js b/spec/frontend/jobs/components/job/manual_variables_form_spec.js
deleted file mode 100644
index 989fe5c11e9..00000000000
--- a/spec/frontend/jobs/components/job/manual_variables_form_spec.js
+++ /dev/null
@@ -1,364 +0,0 @@
-import { GlSprintf, GlLink } from '@gitlab/ui';
-import { createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import { nextTick } from 'vue';
-import { createAlert } from '~/alert';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { TYPENAME_CI_BUILD } from '~/graphql_shared/constants';
-import { JOB_GRAPHQL_ERRORS } from '~/jobs/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import waitForPromises from 'helpers/wait_for_promises';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-import getJobQuery from '~/jobs/components/job/graphql/queries/get_job.query.graphql';
-import playJobMutation from '~/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql';
-import retryJobMutation from '~/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql';
-
-import {
- mockFullPath,
- mockId,
- mockJobResponse,
- mockJobWithVariablesResponse,
- mockJobPlayMutationData,
- mockJobRetryMutationData,
-} from './mock_data';
-
-const localVue = createLocalVue();
-jest.mock('~/alert');
-localVue.use(VueApollo);
-
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- redirectTo: jest.fn(),
-}));
-
-const defaultProvide = {
- projectPath: mockFullPath,
-};
-
-describe('Manual Variables Form', () => {
- let wrapper;
- let mockApollo;
- let requestHandlers;
-
- const getJobQueryResponseHandlerWithVariables = jest.fn().mockResolvedValue(mockJobResponse);
- const playJobMutationHandler = jest.fn().mockResolvedValue({});
- const retryJobMutationHandler = jest.fn().mockResolvedValue({});
-
- const defaultHandlers = {
- getJobQueryResponseHandlerWithVariables,
- playJobMutationHandler,
- retryJobMutationHandler,
- };
-
- const createComponent = ({ props = {}, handlers = defaultHandlers } = {}) => {
- requestHandlers = handlers;
-
- mockApollo = createMockApollo([
- [getJobQuery, handlers.getJobQueryResponseHandlerWithVariables],
- [playJobMutation, handlers.playJobMutationHandler],
- [retryJobMutation, handlers.retryJobMutationHandler],
- ]);
-
- const options = {
- localVue,
- apolloProvider: mockApollo,
- };
-
- wrapper = mountExtended(ManualVariablesForm, {
- propsData: {
- jobId: mockId,
- isRetryable: false,
- ...props,
- },
- provide: {
- ...defaultProvide,
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- const findHelpText = () => wrapper.findComponent(GlSprintf);
- const findHelpLink = () => wrapper.findComponent(GlLink);
- const findCancelBtn = () => wrapper.findByTestId('cancel-btn');
- const findRunBtn = () => wrapper.findByTestId('run-manual-job-btn');
- const findDeleteVarBtn = () => wrapper.findByTestId('delete-variable-btn');
- const findAllDeleteVarBtns = () => wrapper.findAllByTestId('delete-variable-btn');
- const findDeleteVarBtnPlaceholder = () => wrapper.findByTestId('delete-variable-btn-placeholder');
- const findCiVariableKey = () => wrapper.findByTestId('ci-variable-key');
- const findAllCiVariableKeys = () => wrapper.findAllByTestId('ci-variable-key');
- const findCiVariableValue = () => wrapper.findByTestId('ci-variable-value');
- const findAllVariables = () => wrapper.findAllByTestId('ci-variable-row');
-
- const setCiVariableKey = () => {
- findCiVariableKey().setValue('new key');
- findCiVariableKey().vm.$emit('change');
- nextTick();
- };
-
- const setCiVariableKeyByPosition = (position, value) => {
- findAllCiVariableKeys().at(position).setValue(value);
- findAllCiVariableKeys().at(position).vm.$emit('change');
- nextTick();
- };
-
- afterEach(() => {
- createAlert.mockClear();
- });
-
- describe('when page renders', () => {
- beforeEach(async () => {
- await createComponent();
- });
-
- it('renders help text with provided link', () => {
- expect(findHelpText().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(
- '/help/ci/variables/index#add-a-cicd-variable-to-a-project',
- );
- });
- });
-
- describe('when query is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', () => {
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobQueryErrorText,
- });
- });
- });
-
- describe('when job has not been retried', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest
- .fn()
- .mockResolvedValue(mockJobWithVariablesResponse),
- },
- });
- });
-
- it('does not render the cancel button', () => {
- expect(findCancelBtn().exists()).toBe(false);
- expect(findRunBtn().exists()).toBe(true);
- });
- });
-
- describe('when job has variables', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest
- .fn()
- .mockResolvedValue(mockJobWithVariablesResponse),
- },
- });
- });
-
- it('sets manual job variables', () => {
- const queryKey = mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].key;
- const queryValue =
- mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].value;
-
- expect(findCiVariableKey().element.value).toBe(queryKey);
- expect(findCiVariableValue().element.value).toBe(queryValue);
- });
- });
-
- describe('when play mutation fires', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- playJobMutationHandler: jest.fn().mockResolvedValue(mockJobPlayMutationData),
- },
- });
- });
-
- it('passes variables in correct format', async () => {
- await setCiVariableKey();
-
- await findCiVariableValue().setValue('new value');
-
- await findRunBtn().vm.$emit('click');
-
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledWith({
- id: convertToGraphQLId(TYPENAME_CI_BUILD, mockId),
- variables: [
- {
- key: 'new key',
- value: 'new value',
- },
- ],
- });
- });
-
- it('redirects to job properly after job is run', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(mockJobPlayMutationData.data.jobPlay.job.webPath); // eslint-disable-line import/no-deprecated
- });
- });
-
- describe('when play mutation is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- playJobMutationHandler: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
- });
- });
- });
-
- describe('when job is retryable', () => {
- beforeEach(async () => {
- await createComponent({
- props: { isRetryable: true },
- handlers: {
- retryJobMutationHandler: jest.fn().mockResolvedValue(mockJobRetryMutationData),
- },
- });
- });
-
- it('renders cancel button', () => {
- expect(findCancelBtn().exists()).toBe(true);
- });
-
- it('redirects to job properly after rerun', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(requestHandlers.retryJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(mockJobRetryMutationData.data.jobRetry.job.webPath); // eslint-disable-line import/no-deprecated
- });
- });
-
- describe('when retry mutation is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- props: { isRetryable: true },
- handlers: {
- retryJobMutationHandler: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
- });
- });
- });
-
- describe('updating variables in UI', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
- },
- });
- });
-
- it('creates a new variable when user enters a new key value', async () => {
- expect(findAllVariables()).toHaveLength(1);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
- });
-
- it('does not create extra empty variables', async () => {
- expect(findAllVariables()).toHaveLength(1);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
- });
-
- it('removes the correct variable row', async () => {
- const variableKeyNameOne = 'key-one';
- const variableKeyNameThree = 'key-three';
-
- await setCiVariableKeyByPosition(0, variableKeyNameOne);
-
- await setCiVariableKeyByPosition(1, 'key-two');
-
- await setCiVariableKeyByPosition(2, variableKeyNameThree);
-
- expect(findAllVariables()).toHaveLength(4);
-
- await findAllDeleteVarBtns().at(1).trigger('click');
-
- expect(findAllVariables()).toHaveLength(3);
-
- expect(findAllCiVariableKeys().at(0).element.value).toBe(variableKeyNameOne);
- expect(findAllCiVariableKeys().at(1).element.value).toBe(variableKeyNameThree);
- expect(findAllCiVariableKeys().at(2).element.value).toBe('');
- });
-
- it('delete variable button should only show when there is more than one variable', async () => {
- expect(findDeleteVarBtn().exists()).toBe(false);
-
- await setCiVariableKey();
-
- expect(findDeleteVarBtn().exists()).toBe(true);
- });
- });
-
- describe('variable delete button placeholder', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
- },
- });
- });
-
- it('delete variable button placeholder should only exist when a user cannot remove', () => {
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
- });
-
- it('does not show the placeholder button', () => {
- expect(findDeleteVarBtnPlaceholder().classes('gl-opacity-0')).toBe(true);
- });
-
- it('placeholder button will not delete the row on click', async () => {
- expect(findAllCiVariableKeys()).toHaveLength(1);
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
-
- await findDeleteVarBtnPlaceholder().trigger('click');
-
- expect(findAllCiVariableKeys()).toHaveLength(1);
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/mock_data.js b/spec/frontend/jobs/components/job/mock_data.js
deleted file mode 100644
index fb3a361c9c9..00000000000
--- a/spec/frontend/jobs/components/job/mock_data.js
+++ /dev/null
@@ -1,123 +0,0 @@
-export const mockFullPath = 'Commit451/lab-coat';
-export const mockId = 401;
-
-export const mockJobResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/4',
- job: {
- id: 'gid://gitlab/Ci::Build/401',
- manualJob: true,
- manualVariables: {
- nodes: [],
- __typename: 'CiManualVariableConnection',
- },
- name: 'manual_job',
- retryable: true,
- status: 'SUCCESS',
- __typename: 'CiJob',
- },
- __typename: 'Project',
- },
- },
-};
-
-export const mockJobWithVariablesResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/4',
- job: {
- id: 'gid://gitlab/Ci::Build/401',
- manualJob: true,
- manualVariables: {
- nodes: [
- {
- id: 'gid://gitlab/Ci::JobVariable/150',
- key: 'new key',
- value: 'new value',
- __typename: 'CiManualVariable',
- },
- ],
- __typename: 'CiManualVariableConnection',
- },
- name: 'manual_job',
- retryable: true,
- status: 'SUCCESS',
- __typename: 'CiJob',
- },
- __typename: 'Project',
- },
- },
-};
-
-export const mockJobPlayMutationData = {
- data: {
- jobPlay: {
- job: {
- id: 'gid://gitlab/Ci::Build/401',
- manualVariables: {
- nodes: [
- {
- id: 'gid://gitlab/Ci::JobVariable/151',
- key: 'new key',
- value: 'new value',
- __typename: 'CiManualVariable',
- },
- ],
- __typename: 'CiManualVariableConnection',
- },
- webPath: '/Commit451/lab-coat/-/jobs/401',
- __typename: 'CiJob',
- },
- errors: [],
- __typename: 'JobPlayPayload',
- },
- },
-};
-
-export const mockJobRetryMutationData = {
- data: {
- jobRetry: {
- job: {
- id: 'gid://gitlab/Ci::Build/401',
- manualVariables: {
- nodes: [
- {
- id: 'gid://gitlab/Ci::JobVariable/151',
- key: 'new key',
- value: 'new value',
- __typename: 'CiManualVariable',
- },
- ],
- __typename: 'CiManualVariableConnection',
- },
- webPath: '/Commit451/lab-coat/-/jobs/401',
- __typename: 'CiJob',
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const mockPendingJobData = {
- has_trace: false,
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- illustration: {
- image: 'path',
- size: '340',
- title: '',
- content: '',
- },
- action: {
- button_title: 'Retry job',
- method: 'post',
- path: '/path',
- },
- },
-};
diff --git a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js b/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
deleted file mode 100644
index 546f5392caf..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import SidebarDetailRow from '~/jobs/components/job/sidebar/sidebar_detail_row.vue';
-import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
-
-describe('Sidebar detail row', () => {
- let wrapper;
-
- const title = 'this is the title';
- const value = 'this is the value';
- const helpUrl = `${DOCS_URL}/runner/register/index.html`;
- const path = 'path/to/value';
-
- const findHelpLink = () => wrapper.findByTestId('job-sidebar-help-link');
- const findValueLink = () => wrapper.findByTestId('job-sidebar-value-link');
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(SidebarDetailRow, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with title/value and without helpUrl/path', () => {
- beforeEach(() => {
- createComponent({ title, value });
- });
-
- it('should render the provided title and value', () => {
- expect(wrapper.text()).toBe(`${title}: ${value}`);
- });
-
- it('should not render the help link', () => {
- expect(findHelpLink().exists()).toBe(false);
- });
-
- it('should not render the value link', () => {
- expect(findValueLink().exists()).toBe(false);
- });
- });
-
- describe('when helpUrl provided', () => {
- beforeEach(() => {
- createComponent({
- helpUrl,
- title,
- value,
- });
- });
-
- it('should render the help link', () => {
- expect(findHelpLink().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(helpUrl);
- });
- });
-
- describe('when path is provided', () => {
- it('should render link to value', () => {
- createComponent({
- path,
- title,
- value,
- });
-
- expect(findValueLink().attributes('href')).toBe(path);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/sidebar_header_spec.js b/spec/frontend/jobs/components/job/sidebar_header_spec.js
deleted file mode 100644
index cf182330578..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_header_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import SidebarHeader from '~/jobs/components/job/sidebar/sidebar_header.vue';
-import JobRetryButton from '~/jobs/components/job/sidebar/job_sidebar_retry_button.vue';
-import getJobQuery from '~/jobs/components/job/graphql/queries/get_job.query.graphql';
-import { mockFullPath, mockId, mockJobResponse } from './mock_data';
-
-Vue.use(VueApollo);
-
-const defaultProvide = {
- projectPath: mockFullPath,
-};
-
-describe('Sidebar Header', () => {
- let wrapper;
-
- const createComponent = ({ options = {}, props = {}, restJob = {} } = {}) => {
- wrapper = shallowMountExtended(SidebarHeader, {
- propsData: {
- ...props,
- jobId: mockId,
- restJob,
- },
- provide: {
- ...defaultProvide,
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = ({ props = {}, restJob = {} } = {}) => {
- const getJobQueryResponse = jest.fn().mockResolvedValue(mockJobResponse);
-
- const requestHandlers = [[getJobQuery, getJobQueryResponse]];
-
- const apolloProvider = createMockApollo(requestHandlers);
-
- const options = {
- apolloProvider,
- };
-
- createComponent({
- props,
- restJob,
- options,
- });
-
- return waitForPromises();
- };
-
- const findCancelButton = () => wrapper.findByTestId('cancel-button');
- const findEraseButton = () => wrapper.findByTestId('job-log-erase-link');
- const findJobName = () => wrapper.findByTestId('job-name');
- const findRetryButton = () => wrapper.findComponent(JobRetryButton);
-
- describe('when rendering contents', () => {
- it('renders the correct job name', async () => {
- await createComponentWithApollo();
- expect(findJobName().text()).toBe(mockJobResponse.data.project.job.name);
- });
-
- it('does not render buttons with no paths', async () => {
- await createComponentWithApollo();
- expect(findCancelButton().exists()).toBe(false);
- expect(findEraseButton().exists()).toBe(false);
- expect(findRetryButton().exists()).toBe(false);
- });
-
- it('renders a retry button with a path', async () => {
- await createComponentWithApollo({ restJob: { retry_path: 'retry/path' } });
- expect(findRetryButton().exists()).toBe(true);
- });
-
- it('renders a cancel button with a path', async () => {
- await createComponentWithApollo({ restJob: { cancel_path: 'cancel/path' } });
- expect(findCancelButton().exists()).toBe(true);
- });
-
- it('renders an erase button with a path', async () => {
- await createComponentWithApollo({ restJob: { erase_path: 'erase/path' } });
- expect(findEraseButton().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/sidebar_spec.js b/spec/frontend/jobs/components/job/sidebar_spec.js
deleted file mode 100644
index fbff64b4d78..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import MockAdapter from 'axios-mock-adapter';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import ArtifactsBlock from '~/jobs/components/job/sidebar/artifacts_block.vue';
-import JobRetryForwardDeploymentModal from '~/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue';
-import JobsContainer from '~/jobs/components/job/sidebar/jobs_container.vue';
-import Sidebar from '~/jobs/components/job/sidebar/sidebar.vue';
-import StagesDropdown from '~/jobs/components/job/sidebar/stages_dropdown.vue';
-import createStore from '~/jobs/store';
-import job, { jobsInStage } from '../../mock_data';
-
-describe('Sidebar details block', () => {
- let mock;
- let store;
- let wrapper;
-
- const forwardDeploymentFailure = 'forward_deployment_failure';
- const findModal = () => wrapper.findComponent(JobRetryForwardDeploymentModal);
- const findArtifactsBlock = () => wrapper.findComponent(ArtifactsBlock);
- const findNewIssueButton = () => wrapper.findByTestId('job-new-issue');
- const findTerminalLink = () => wrapper.findByTestId('terminal-link');
- const findJobStagesDropdown = () => wrapper.findComponent(StagesDropdown);
- const findJobsContainer = () => wrapper.findComponent(JobsContainer);
-
- const createWrapper = (props) => {
- store = createStore();
-
- store.state.job = job;
-
- wrapper = extendedWrapper(
- shallowMount(Sidebar, {
- propsData: {
- ...props,
- },
-
- store,
- }),
- );
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onGet().reply(HTTP_STATUS_OK, {
- name: job.stage,
- });
- });
-
- describe('without terminal path', () => {
- it('does not render terminal link', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findTerminalLink().exists()).toBe(false);
- });
- });
-
- describe('with terminal path', () => {
- it('renders terminal link', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', { ...job, terminal_path: 'job/43123/terminal' });
-
- expect(findTerminalLink().exists()).toBe(true);
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', job);
- });
-
- it('should render link to new issue', () => {
- expect(findNewIssueButton().attributes('href')).toBe(job.new_issue_path);
- expect(findNewIssueButton().text()).toBe('New issue');
- });
- });
-
- describe('forward deployment failure', () => {
- describe('when the relevant data is missing', () => {
- it.each`
- retryPath | failureReason
- ${null} | ${null}
- ${''} | ${''}
- ${job.retry_path} | ${''}
- ${''} | ${forwardDeploymentFailure}
- ${job.retry_path} | ${'unmet_prerequisites'}
- `(
- 'should not render the modal when path and failure are $retryPath, $failureReason',
- async ({ retryPath, failureReason }) => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', {
- ...job,
- failure_reason: failureReason,
- retry_path: retryPath,
- });
- expect(findModal().exists()).toBe(false);
- },
- );
- });
-
- describe('when there is the relevant error', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', {
- ...job,
- failure_reason: forwardDeploymentFailure,
- });
- });
-
- it('should render the modal', () => {
- expect(findModal().exists()).toBe(true);
- });
- });
- });
-
- describe('stages dropdown', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', job);
- });
-
- describe('with stages', () => {
- it('renders value provided as selectedStage as selected', () => {
- expect(findJobStagesDropdown().props('selectedStage')).toBe(job.stage);
- });
- });
-
- describe('without jobs for stages', () => {
- it('does not render jobs container', () => {
- expect(findJobsContainer().exists()).toBe(false);
- });
- });
-
- describe('with jobs for stages', () => {
- beforeEach(() => {
- return store.dispatch('receiveJobsForStageSuccess', jobsInStage.latest_statuses);
- });
-
- it('renders list of jobs', () => {
- expect(findJobsContainer().exists()).toBe(true);
- });
- });
-
- describe('when job data changes', () => {
- const stageArg = job.pipeline.details.stages.find((stage) => stage.name === job.stage);
-
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
- });
-
- describe('and the job stage is currently selected', () => {
- describe('when the status changed', () => {
- it('refetch the jobs list for the stage', async () => {
- await store.dispatch('receiveJobSuccess', { ...job, status: 'new' });
-
- expect(store.dispatch).toHaveBeenNthCalledWith(2, 'fetchJobsForStage', { ...stageArg });
- });
- });
-
- describe('when the status did not change', () => {
- it('does not refetch the jobs list for the stage', async () => {
- await store.dispatch('receiveJobSuccess', { ...job });
-
- expect(store.dispatch).toHaveBeenCalledTimes(1);
- expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
- ...job,
- });
- });
- });
- });
-
- describe('and the job stage is not currently selected', () => {
- it('does not refetch the jobs list for the stage', async () => {
- // Setting stage to `random` on the job means that we are looking
- // at `build` stage currently, but the job we are seeing in the logs
- // belong to `random`, so we shouldn't have to refetch
- await store.dispatch('receiveJobSuccess', { ...job, stage: 'random' });
-
- expect(store.dispatch).toHaveBeenCalledTimes(1);
- expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
- ...job,
- stage: 'random',
- });
- });
- });
- });
- });
-
- describe('artifacts', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('artifacts are not shown if there are no properties other than locked', () => {
- expect(findArtifactsBlock().exists()).toBe(false);
- });
-
- it('artifacts are shown if present', async () => {
- store.state.job.artifact = {
- download_path: '/root/ci-project/-/jobs/1960/artifacts/download',
- browse_path: '/root/ci-project/-/jobs/1960/artifacts/browse',
- keep_path: '/root/ci-project/-/jobs/1960/artifacts/keep',
- expire_at: '2021-03-23T17:57:11.211Z',
- expired: false,
- locked: false,
- };
-
- await nextTick();
-
- expect(findArtifactsBlock().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/stages_dropdown_spec.js b/spec/frontend/jobs/components/job/stages_dropdown_spec.js
deleted file mode 100644
index c42edc62183..00000000000
--- a/spec/frontend/jobs/components/job/stages_dropdown_spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import { GlDisclosureDropdown, GlLink, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { Mousetrap } from '~/lib/mousetrap';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import StagesDropdown from '~/jobs/components/job/sidebar/stages_dropdown.vue';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import * as copyToClipboard from '~/behaviors/copy_to_clipboard';
-import {
- mockPipelineWithoutRef,
- mockPipelineWithoutMR,
- mockPipelineWithAttachedMR,
- mockPipelineDetached,
-} from '../../mock_data';
-
-describe('Stages Dropdown', () => {
- let wrapper;
-
- const findStatus = () => wrapper.findComponent(CiIcon);
- const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
- const findSelectedStageText = () => findDropdown().props('toggleText');
-
- const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text();
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(StagesDropdown, {
- propsData: {
- stages: [],
- selectedStage: 'deploy',
- ...props,
- },
- stubs: {
- GlSprintf,
- GlLink,
- },
- }),
- );
- };
-
- describe('without a merge request pipeline', () => {
- beforeEach(() => {
- createComponent({
- pipeline: mockPipelineWithoutMR,
- stages: [{ name: 'build' }, { name: 'test' }],
- });
- });
-
- it('renders pipeline status', () => {
- expect(findStatus().exists()).toBe(true);
- });
-
- it('renders dropdown with stages', () => {
- expect(findDropdown().props('items')).toEqual([
- expect.objectContaining({ text: 'build' }),
- expect.objectContaining({ text: 'test' }),
- ]);
- });
-
- it('renders selected stage', () => {
- expect(findSelectedStageText()).toBe('deploy');
- });
- });
-
- describe('pipelineInfo', () => {
- const allElements = [
- 'pipeline-path',
- 'mr-link',
- 'source-ref-link',
- 'copy-source-ref-link',
- 'source-branch-link',
- 'copy-source-branch-link',
- 'target-branch-link',
- 'copy-target-branch-link',
- ];
- describe.each([
- [
- 'does not have a ref',
- {
- pipeline: mockPipelineWithoutRef,
- text: `Pipeline #${mockPipelineWithoutRef.id}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutRef.path }] },
- ],
- },
- ],
- [
- 'hasRef but not triggered by MR',
- {
- pipeline: mockPipelineWithoutMR,
- text: `Pipeline #${mockPipelineWithoutMR.id} for ${mockPipelineWithoutMR.ref.name}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutMR.path }] },
- { testId: 'source-ref-link', props: [{ href: mockPipelineWithoutMR.ref.path }] },
- { testId: 'copy-source-ref-link', props: [{ text: mockPipelineWithoutMR.ref.name }] },
- ],
- },
- ],
- [
- 'hasRef and MR but not MR pipeline',
- {
- pipeline: mockPipelineDetached,
- text: `Pipeline #${mockPipelineDetached.id} for !${mockPipelineDetached.merge_request.iid} with ${mockPipelineDetached.merge_request.source_branch}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineDetached.path }] },
- { testId: 'mr-link', props: [{ href: mockPipelineDetached.merge_request.path }] },
- {
- testId: 'source-branch-link',
- props: [{ href: mockPipelineDetached.merge_request.source_branch_path }],
- },
- {
- testId: 'copy-source-branch-link',
- props: [{ text: mockPipelineDetached.merge_request.source_branch }],
- },
- ],
- },
- ],
- [
- 'hasRef and MR and MR pipeline',
- {
- pipeline: mockPipelineWithAttachedMR,
- text: `Pipeline #${mockPipelineWithAttachedMR.id} for !${mockPipelineWithAttachedMR.merge_request.iid} with ${mockPipelineWithAttachedMR.merge_request.source_branch} into ${mockPipelineWithAttachedMR.merge_request.target_branch}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithAttachedMR.path }] },
- { testId: 'mr-link', props: [{ href: mockPipelineWithAttachedMR.merge_request.path }] },
- {
- testId: 'source-branch-link',
- props: [{ href: mockPipelineWithAttachedMR.merge_request.source_branch_path }],
- },
- {
- testId: 'copy-source-branch-link',
- props: [{ text: mockPipelineWithAttachedMR.merge_request.source_branch }],
- },
- {
- testId: 'target-branch-link',
- props: [{ href: mockPipelineWithAttachedMR.merge_request.target_branch_path }],
- },
- {
- testId: 'copy-target-branch-link',
- props: [{ text: mockPipelineWithAttachedMR.merge_request.target_branch }],
- },
- ],
- },
- ],
- ])('%s', (_, { pipeline, text, foundElements }) => {
- beforeEach(() => {
- createComponent({
- pipeline,
- });
- });
-
- it('should render the text', () => {
- expect(findPipelineInfoText()).toMatchInterpolatedText(text);
- });
-
- it('should find components with props', () => {
- foundElements.forEach((element) => {
- element.props.forEach((prop) => {
- const key = Object.keys(prop)[0];
- expect(wrapper.findByTestId(element.testId).attributes(key)).toBe(prop[key]);
- });
- });
- });
-
- it('should not find components', () => {
- const foundTestIds = foundElements.map((element) => element.testId);
- allElements
- .filter((testId) => !foundTestIds.includes(testId))
- .forEach((testId) => {
- expect(wrapper.findByTestId(testId).exists()).toBe(false);
- });
- });
- });
- });
-
- describe('mousetrap', () => {
- it.each([
- ['copy-source-ref-link', mockPipelineWithoutMR],
- ['copy-source-branch-link', mockPipelineWithAttachedMR],
- ])(
- 'calls clickCopyToClipboardButton with `%s` button when `b` is pressed',
- (button, pipeline) => {
- const copyToClipboardMock = jest.spyOn(copyToClipboard, 'clickCopyToClipboardButton');
- createComponent({ pipeline });
-
- Mousetrap.trigger('b');
-
- expect(copyToClipboardMock).toHaveBeenCalledWith(wrapper.findByTestId(button).element);
- },
- );
- });
-});
diff --git a/spec/frontend/jobs/components/job/stuck_block_spec.js b/spec/frontend/jobs/components/job/stuck_block_spec.js
deleted file mode 100644
index 0f014a9222b..00000000000
--- a/spec/frontend/jobs/components/job/stuck_block_spec.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import { GlBadge, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import StuckBlock from '~/jobs/components/job/stuck_block.vue';
-
-describe('Stuck Block Job component', () => {
- let wrapper;
-
- const createWrapper = (props) => {
- wrapper = shallowMount(StuckBlock, {
- propsData: {
- ...props,
- },
- });
- };
-
- const tags = ['docker', 'gitlab-org'];
-
- const findStuckNoActiveRunners = () =>
- wrapper.find('[data-testid="job-stuck-no-active-runners"]');
- const findStuckNoRunners = () => wrapper.find('[data-testid="job-stuck-no-runners"]');
- const findStuckWithTags = () => wrapper.find('[data-testid="job-stuck-with-tags"]');
- const findRunnerPathLink = () => wrapper.findComponent(GlLink);
- const findAllBadges = () => wrapper.findAllComponents(GlBadge);
-
- describe('with no runners for project', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: true,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders only information about project not having runners', () => {
- expect(findStuckNoRunners().exists()).toBe(true);
- expect(findStuckWithTags().exists()).toBe(false);
- expect(findStuckNoActiveRunners().exists()).toBe(false);
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-
- describe('with tags', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: false,
- tags,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders information about the tags not being set', () => {
- expect(findStuckWithTags().exists()).toBe(true);
- expect(findStuckNoActiveRunners().exists()).toBe(false);
- expect(findStuckNoRunners().exists()).toBe(false);
- });
-
- it('renders tags', () => {
- findAllBadges().wrappers.forEach((badgeElt, index) => {
- return expect(badgeElt.text()).toBe(tags[index]);
- });
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-
- describe('without active runners', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: false,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders information about project not having runners', () => {
- expect(findStuckNoActiveRunners().exists()).toBe(true);
- expect(findStuckNoRunners().exists()).toBe(false);
- expect(findStuckWithTags().exists()).toBe(false);
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/trigger_block_spec.js b/spec/frontend/jobs/components/job/trigger_block_spec.js
deleted file mode 100644
index 8bb2c1f3ad8..00000000000
--- a/spec/frontend/jobs/components/job/trigger_block_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { GlButton, GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import TriggerBlock from '~/jobs/components/job/sidebar/trigger_block.vue';
-
-describe('Trigger block', () => {
- let wrapper;
-
- const findRevealButton = () => wrapper.findComponent(GlButton);
- const findVariableTable = () => wrapper.findComponent(GlTableLite);
- const findShortToken = () => wrapper.find('[data-testid="trigger-short-token"]');
- const findVariableValue = (index) =>
- wrapper.findAll('[data-testid="trigger-build-value"]').at(index);
- const findVariableKey = (index) => wrapper.findAll('[data-testid="trigger-build-key"]').at(index);
-
- const createComponent = (props) => {
- wrapper = mount(TriggerBlock, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with short token and no variables', () => {
- it('renders short token', () => {
- createComponent({
- trigger: {
- short_token: '0a666b2',
- variables: [],
- },
- });
-
- expect(findShortToken().text()).toContain('0a666b2');
- });
- });
-
- describe('without variables or short token', () => {
- beforeEach(() => {
- createComponent({ trigger: { variables: [] } });
- });
-
- it('does not render short token', () => {
- expect(findShortToken().exists()).toBe(false);
- });
-
- it('does not render variables', () => {
- expect(findRevealButton().exists()).toBe(false);
- expect(findVariableTable().exists()).toBe(false);
- });
- });
-
- describe('with variables', () => {
- describe('hide/reveal variables', () => {
- it('should toggle variables on click', async () => {
- const hiddenValue = '••••••';
- const gcsVar = { key: 'UPLOAD_TO_GCS', value: 'false', public: false };
- const s3Var = { key: 'UPLOAD_TO_S3', value: 'true', public: false };
-
- createComponent({
- trigger: {
- variables: [gcsVar, s3Var],
- },
- });
-
- expect(findRevealButton().text()).toBe('Reveal values');
-
- expect(findVariableValue(0).text()).toBe(hiddenValue);
- expect(findVariableValue(1).text()).toBe(hiddenValue);
-
- expect(findVariableKey(0).text()).toBe(gcsVar.key);
- expect(findVariableKey(1).text()).toBe(s3Var.key);
-
- await findRevealButton().trigger('click');
-
- expect(findRevealButton().text()).toBe('Hide values');
-
- expect(findVariableValue(0).text()).toBe(gcsVar.value);
- expect(findVariableValue(1).text()).toBe(s3Var.value);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js b/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
deleted file mode 100644
index 1072cdd6781..00000000000
--- a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { GlAlert, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import UnmetPrerequisitesBlock from '~/jobs/components/job/unmet_prerequisites_block.vue';
-
-describe('Unmet Prerequisites Block Job component', () => {
- let wrapper;
- const helpPath = '/user/project/clusters/index.html#troubleshooting-failed-deployment-jobs';
-
- const createComponent = () => {
- wrapper = shallowMount(UnmetPrerequisitesBlock, {
- propsData: {
- helpPath,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('renders an alert with the correct message', () => {
- const container = wrapper.findComponent(GlAlert);
- const alertMessage =
- 'This job failed because the necessary resources were not successfully created.';
-
- expect(container).not.toBeNull();
- expect(container.text()).toContain(alertMessage);
- });
-
- it('renders link to help page', () => {
- const helpLink = wrapper.findComponent(GlLink);
-
- expect(helpLink).not.toBeNull();
- expect(helpLink.text()).toContain('More information');
- expect(helpLink.attributes().href).toEqual(helpPath);
- });
-});
diff --git a/spec/frontend/jobs/components/log/collapsible_section_spec.js b/spec/frontend/jobs/components/log/collapsible_section_spec.js
deleted file mode 100644
index 5adedea28a5..00000000000
--- a/spec/frontend/jobs/components/log/collapsible_section_spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import CollapsibleSection from '~/jobs/components/log/collapsible_section.vue';
-import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data';
-
-describe('Job Log Collapsible Section', () => {
- let wrapper;
-
- const jobLogEndpoint = 'jobs/335';
-
- const findCollapsibleLine = () => wrapper.find('.collapsible-line');
- const findCollapsibleLineSvg = () => wrapper.find('.collapsible-line svg');
-
- const createComponent = (props = {}) => {
- wrapper = mount(CollapsibleSection, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with closed section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionClosed,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the closed state', () => {
- expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-right-icon');
- });
- });
-
- describe('with opened section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the open state', () => {
- expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-down-icon');
- });
-
- it('renders collapsible lines content', () => {
- expect(wrapper.findAll('.js-line').length).toEqual(collapsibleSectionOpened.lines.length);
- });
- });
-
- it('emits onClickCollapsibleLine on click', async () => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
-
- findCollapsibleLine().trigger('click');
-
- await nextTick();
- expect(wrapper.emitted('onClickCollapsibleLine').length).toBe(1);
- });
-});
diff --git a/spec/frontend/jobs/components/log/duration_badge_spec.js b/spec/frontend/jobs/components/log/duration_badge_spec.js
deleted file mode 100644
index 644d05366a0..00000000000
--- a/spec/frontend/jobs/components/log/duration_badge_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import DurationBadge from '~/jobs/components/log/duration_badge.vue';
-
-describe('Job Log Duration Badge', () => {
- let wrapper;
-
- const data = {
- duration: '00:30:01',
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(DurationBadge, {
- propsData: {
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders provided duration', () => {
- expect(wrapper.text()).toBe(data.duration);
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_header_spec.js b/spec/frontend/jobs/components/log/line_header_spec.js
deleted file mode 100644
index c02d8c22655..00000000000
--- a/spec/frontend/jobs/components/log/line_header_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import DurationBadge from '~/jobs/components/log/duration_badge.vue';
-import LineHeader from '~/jobs/components/log/line_header.vue';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-
-describe('Job Log Header Line', () => {
- let wrapper;
-
- const data = {
- line: {
- content: [
- {
- text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
- style: 'term-fg-l-green',
- },
- ],
- lineNumber: 76,
- },
- isClosed: true,
- path: '/jashkenas/underscore/-/jobs/335',
- };
-
- const createComponent = (props = {}) => {
- wrapper = mount(LineHeader, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('line', () => {
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders the line number component', () => {
- expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
- });
-
- it('renders a span the provided text', () => {
- expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
- });
-
- it('renders the provided style as a class attribute', () => {
- expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
- });
- });
-
- describe('when isCloses is true', () => {
- beforeEach(() => {
- createComponent({ ...data, isClosed: true });
- });
-
- it('sets icon name to be chevron-lg-right', () => {
- expect(wrapper.vm.iconName).toEqual('chevron-lg-right');
- });
- });
-
- describe('when isCloses is false', () => {
- beforeEach(() => {
- createComponent({ ...data, isClosed: false });
- });
-
- it('sets icon name to be chevron-lg-down', () => {
- expect(wrapper.vm.iconName).toEqual('chevron-lg-down');
- });
- });
-
- describe('on click', () => {
- beforeEach(() => {
- createComponent(data);
- });
-
- it('emits toggleLine event', async () => {
- wrapper.trigger('click');
-
- await nextTick();
- expect(wrapper.emitted().toggleLine.length).toBe(1);
- });
- });
-
- describe('with duration', () => {
- beforeEach(() => {
- createComponent({ ...data, duration: '00:10' });
- });
-
- it('renders the duration badge', () => {
- expect(wrapper.findComponent(DurationBadge).exists()).toBe(true);
- });
- });
-
- describe('line highlighting', () => {
- describe('with hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
-
- createComponent(data);
- });
-
- it('highlights line', () => {
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
- });
-
- describe('without hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
-
- createComponent(data);
- });
-
- it('does not highlight line', () => {
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_number_spec.js b/spec/frontend/jobs/components/log/line_number_spec.js
deleted file mode 100644
index 4130c124a30..00000000000
--- a/spec/frontend/jobs/components/log/line_number_spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-
-describe('Job Log Line Number', () => {
- let wrapper;
-
- const data = {
- lineNumber: 0,
- path: '/jashkenas/underscore/-/jobs/335',
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(LineNumber, {
- propsData: {
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders incremented lineNunber by 1', () => {
- expect(wrapper.text()).toBe('1');
- });
-
- it('renders link with lineNumber as an ID', () => {
- expect(wrapper.attributes().id).toBe('L1');
- });
-
- it('links to the provided path with line number as anchor', () => {
- expect(wrapper.attributes().href).toBe(`${data.path}#L1`);
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_spec.js b/spec/frontend/jobs/components/log/line_spec.js
deleted file mode 100644
index fad7a03beef..00000000000
--- a/spec/frontend/jobs/components/log/line_spec.js
+++ /dev/null
@@ -1,267 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Line from '~/jobs/components/log/line.vue';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-
-const httpUrl = 'http://example.com';
-const httpsUrl = 'https://example.com';
-const queryUrl = 'https://example.com?param=val';
-
-const mockProps = ({ text = 'Running with gitlab-runner 12.1.0 (de7731dd)' } = {}) => ({
- line: {
- content: [
- {
- text,
- style: 'term-fg-l-green',
- },
- ],
- lineNumber: 0,
- },
- path: '/jashkenas/underscore/-/jobs/335',
-});
-
-describe('Job Log Line', () => {
- let wrapper;
- let data;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(Line, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findLine = () => wrapper.find('span');
- const findLink = () => findLine().find('a');
- const findLinks = () => findLine().findAll('a');
- const findLinkAttributeByIndex = (i) => findLinks().at(i).attributes();
-
- beforeEach(() => {
- data = mockProps();
- createComponent(data);
- });
-
- it('renders the line number component', () => {
- expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
- });
-
- it('renders a span the provided text', () => {
- expect(findLine().text()).toBe(data.line.content[0].text);
- });
-
- it('renders the provided style as a class attribute', () => {
- expect(findLine().classes()).toContain(data.line.content[0].style);
- });
-
- describe('job urls as links', () => {
- it('renders an http link', () => {
- createComponent(mockProps({ text: httpUrl }));
-
- expect(findLink().text()).toBe(httpUrl);
- expect(findLink().attributes().href).toBe(httpUrl);
- });
-
- it('renders an https link', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().text()).toBe(httpsUrl);
- expect(findLink().attributes().href).toBe(httpsUrl);
- });
-
- it('renders a link with rel nofollow and noopener', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().attributes().rel).toBe('nofollow noopener noreferrer');
- });
-
- it('renders a link with corresponding styles', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().classes()).toEqual(['gl-reset-color!', 'gl-text-decoration-underline']);
- });
-
- it('renders links with queries, surrounded by questions marks', () => {
- createComponent(mockProps({ text: `Did you see my url ${queryUrl}??` }));
-
- expect(findLine().text()).toBe('Did you see my url https://example.com?param=val??');
- expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
- });
-
- it('renders links with queries, surrounded by exclamation marks', () => {
- createComponent(mockProps({ text: `No! The ${queryUrl}!?` }));
-
- expect(findLine().text()).toBe('No! The https://example.com?param=val!?');
- expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
- });
-
- it('renders links that have brackets `[]` in their parameters', () => {
- const url = `${httpUrl}?label_name[]=frontend`;
-
- createComponent(mockProps({ text: url }));
-
- expect(findLine().text()).toBe(url);
- expect(findLinks().at(0).text()).toBe(url);
- expect(findLinks().at(0).attributes('href')).toBe(url);
- });
-
- it('renders multiple links surrounded by text', () => {
- createComponent(
- mockProps({ text: `Well, my HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl}` }),
- );
- expect(findLine().text()).toBe(
- 'Well, my HTTP url: http://example.com and my HTTPS url: https://example.com',
- );
-
- expect(findLinks()).toHaveLength(2);
-
- expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(1).href).toBe(httpsUrl);
- });
-
- it('renders multiple links surrounded by text, with other symbols', () => {
- createComponent(
- mockProps({ text: `${httpUrl}, ${httpUrl}: ${httpsUrl}; ${httpsUrl}. ${httpsUrl}...` }),
- );
- expect(findLine().text()).toBe(
- 'http://example.com, http://example.com: https://example.com; https://example.com. https://example.com...',
- );
-
- expect(findLinks()).toHaveLength(5);
-
- expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(1).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(2).href).toBe(httpsUrl);
- expect(findLinkAttributeByIndex(3).href).toBe(httpsUrl);
- expect(findLinkAttributeByIndex(4).href).toBe(httpsUrl);
- });
-
- it('renders multiple links surrounded by brackets', () => {
- createComponent(mockProps({ text: `(${httpUrl}) <${httpUrl}> {${httpsUrl}}` }));
- expect(findLine().text()).toBe(
- '(http://example.com) <http://example.com> {https://example.com}',
- );
-
- const links = findLinks();
-
- expect(links).toHaveLength(3);
-
- expect(links.at(0).text()).toBe(httpUrl);
- expect(links.at(0).attributes('href')).toBe(httpUrl);
-
- expect(links.at(1).text()).toBe(httpUrl);
- expect(links.at(1).attributes('href')).toBe(httpUrl);
-
- expect(links.at(2).text()).toBe(httpsUrl);
- expect(links.at(2).attributes('href')).toBe(httpsUrl);
- });
-
- it('renders text with symbols in it', () => {
- const text = 'apt-get update < /dev/null > /dev/null';
- createComponent(mockProps({ text }));
-
- expect(findLine().text()).toBe(text);
- });
-
- const jshref = 'javascript:doEvil();'; // eslint-disable-line no-script-url
-
- it.each`
- type | text
- ${'html link'} | ${'<a href="#">linked</a>'}
- ${'html script'} | ${'<script>doEvil();</script>'}
- ${'html strong'} | ${'<strong>highlighted</strong>'}
- ${'js'} | ${jshref}
- ${'file'} | ${'file:///a-file'}
- ${'ftp'} | ${'ftp://example.com/file'}
- ${'email'} | ${'email@example.com'}
- ${'no scheme'} | ${'example.com/page'}
- `('does not render a $type link', ({ text }) => {
- createComponent(mockProps({ text }));
- expect(findLink().exists()).toBe(false);
- });
- });
-
- describe('job log search', () => {
- const mockSearchResults = [
- {
- offset: 1533,
- content: [{ text: '$ echo "82.71"', style: 'term-fg-l-green term-bold' }],
- section: 'step-script',
- lineNumber: 20,
- },
- { offset: 1560, content: [{ text: '82.71' }], section: 'step-script', lineNumber: 21 },
- ];
-
- it('applies highlight class to search result elements', () => {
- createComponent({
- line: {
- offset: 1560,
- content: [{ text: '82.71' }],
- section: 'step-script',
- lineNumber: 21,
- },
- path: '/root/ci-project/-/jobs/1089',
- searchResults: mockSearchResults,
- });
-
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
-
- it('does not apply highlight class to search result elements', () => {
- createComponent({
- line: {
- offset: 1560,
- content: [{ text: 'docker' }],
- section: 'step-script',
- lineNumber: 29,
- },
- path: '/root/ci-project/-/jobs/1089',
- searchResults: mockSearchResults,
- });
-
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
-
- describe('job log hash highlighting', () => {
- describe('with hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
- });
-
- it('applies highlight class to job log line', () => {
- createComponent({
- line: {
- offset: 24526,
- content: [{ text: 'job log content' }],
- section: 'custom-section',
- lineNumber: 76,
- },
- path: '/root/ci-project/-/jobs/6353',
- });
-
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
- });
-
- describe('without hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
- });
-
- it('does not apply highlight class to job log line', () => {
- createComponent({
- line: {
- offset: 24500,
- content: [{ text: 'line' }],
- section: 'custom-section',
- lineNumber: 10,
- },
- path: '/root/ci-project/-/jobs/6353',
- });
-
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/log/log_spec.js b/spec/frontend/jobs/components/log/log_spec.js
deleted file mode 100644
index 9407b340950..00000000000
--- a/spec/frontend/jobs/components/log/log_spec.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import waitForPromises from 'helpers/wait_for_promises';
-import { scrollToElement } from '~/lib/utils/common_utils';
-import Log from '~/jobs/components/log/log.vue';
-import LogLineHeader from '~/jobs/components/log/line_header.vue';
-import { logLinesParser } from '~/jobs/store/utils';
-import { jobLog } from './mock_data';
-
-jest.mock('~/lib/utils/common_utils', () => ({
- ...jest.requireActual('~/lib/utils/common_utils'),
- scrollToElement: jest.fn(),
-}));
-
-describe('Job Log', () => {
- let wrapper;
- let actions;
- let state;
- let store;
- let toggleCollapsibleLineMock;
-
- Vue.use(Vuex);
-
- const createComponent = () => {
- wrapper = mount(Log, {
- store,
- });
- };
-
- beforeEach(() => {
- toggleCollapsibleLineMock = jest.fn();
- actions = {
- toggleCollapsibleLine: toggleCollapsibleLineMock,
- };
-
- state = {
- jobLog: logLinesParser(jobLog),
- jobLogEndpoint: 'jobs/id',
- };
-
- store = new Vuex.Store({
- actions,
- state,
- });
- });
-
- const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
-
- describe('line numbers', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders a line number for each open line', () => {
- expect(wrapper.find('#L1').text()).toBe('1');
- expect(wrapper.find('#L2').text()).toBe('2');
- expect(wrapper.find('#L3').text()).toBe('3');
- });
-
- it('links to the provided path and correct line number', () => {
- expect(wrapper.find('#L1').attributes('href')).toBe(`${state.jobLogEndpoint}#L1`);
- });
- });
-
- describe('collapsible sections', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders a clickable header section', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the open state', () => {
- expect(findCollapsibleLine().find('[data-testid="chevron-lg-down-icon"]').exists()).toBe(
- true,
- );
- });
-
- describe('on click header section', () => {
- it('calls toggleCollapsibleLine', () => {
- findCollapsibleLine().trigger('click');
-
- expect(toggleCollapsibleLineMock).toHaveBeenCalled();
- });
- });
- });
-
- describe('anchor scrolling', () => {
- afterEach(() => {
- window.location.hash = '';
- });
-
- describe('when hash is not present', () => {
- it('does not scroll to line number', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(wrapper.find('#L6').exists()).toBe(false);
- expect(scrollToElement).not.toHaveBeenCalled();
- });
- });
-
- describe('when hash is present', () => {
- beforeEach(() => {
- window.location.hash = '#L6';
- });
-
- it('scrolls to line number', async () => {
- createComponent();
-
- state.jobLog = logLinesParser(jobLog, [], '#L6');
- await waitForPromises();
-
- expect(scrollToElement).toHaveBeenCalledTimes(1);
-
- state.jobLog = logLinesParser(jobLog, [], '#L7');
- await waitForPromises();
-
- expect(scrollToElement).toHaveBeenCalledTimes(1);
- });
-
- it('line number within collapsed section is visible', () => {
- state.jobLog = logLinesParser(jobLog, [], '#L6');
-
- createComponent();
-
- expect(wrapper.find('#L6').exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/log/mock_data.js b/spec/frontend/jobs/components/log/mock_data.js
deleted file mode 100644
index fa51b92a044..00000000000
--- a/spec/frontend/jobs/components/log/mock_data.js
+++ /dev/null
@@ -1,218 +0,0 @@
-export const jobLog = [
- {
- offset: 1000,
- content: [{ text: 'Running with gitlab-runner 12.1.0 (de7731dd)' }],
- },
- {
- offset: 1001,
- content: [{ text: ' on docker-auto-scale-com 8a6210b8' }],
- },
- {
- offset: 1002,
- content: [
- {
- text: 'Using Docker executor with image dev.gitlab.org3',
- },
- ],
- section: 'prepare-executor',
- section_header: true,
- },
- {
- offset: 1003,
- content: [{ text: 'Starting service postgres:9.6.14 ...', style: 'text-green' }],
- section: 'prepare-executor',
- },
- {
- offset: 1004,
- content: [
- {
- text: 'Restore cache',
- style: 'term-fg-l-cyan term-bold',
- },
- ],
- section: 'restore-cache',
- section_header: true,
- section_options: {
- collapsed: 'true',
- },
- },
- {
- offset: 1005,
- content: [
- {
- text: 'Checking cache for ruby-gems-debian-bullseye-ruby-3.0-16...',
- style: 'term-fg-l-green term-bold',
- },
- ],
- section: 'restore-cache',
- },
-];
-
-export const utilsMockData = [
- {
- offset: 1001,
- content: [{ text: ' on docker-auto-scale-com 8a6210b8' }],
- },
- {
- offset: 1002,
- content: [
- {
- text:
- 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34',
- },
- ],
- section: 'prepare-executor',
- section_header: true,
- },
- {
- offset: 1003,
- content: [{ text: 'Starting service postgres:9.6.14 ...' }],
- section: 'prepare-executor',
- },
- {
- offset: 1004,
- content: [{ text: 'Pulling docker image postgres:9.6.14 ...', style: 'term-fg-l-green' }],
- section: 'prepare-executor',
- },
- {
- offset: 1005,
- content: [],
- section: 'prepare-executor',
- section_duration: '10:00',
- },
-];
-
-export const originalTrace = [
- {
- offset: 1,
- content: [
- {
- text: 'Downloading',
- },
- ],
- },
-];
-
-export const regularIncremental = [
- {
- offset: 2,
- content: [
- {
- text: 'log line',
- },
- ],
- },
-];
-
-export const regularIncrementalRepeated = [
- {
- offset: 1,
- content: [
- {
- text: 'log line',
- },
- ],
- },
-];
-
-export const headerTrace = [
- {
- offset: 1,
- section_header: true,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
- },
-];
-
-export const headerTraceIncremental = [
- {
- offset: 1,
- section_header: true,
- content: [
- {
- text: 'updated log line',
- },
- ],
- section: 'section',
- },
-];
-
-export const collapsibleTrace = [
- {
- offset: 1,
- section_header: true,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
- },
- {
- offset: 2,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
- },
-];
-
-export const collapsibleTraceIncremental = [
- {
- offset: 2,
- content: [
- {
- text: 'updated log line',
- },
- ],
- section: 'section',
- },
-];
-
-export const collapsibleSectionClosed = {
- offset: 5,
- section_header: true,
- isHeader: true,
- isClosed: true,
- line: {
- content: [{ text: 'foo' }],
- section: 'prepare-script',
- lineNumber: 1,
- },
- section_duration: '00:03',
- lines: [
- {
- offset: 80,
- content: [{ text: 'this is a collapsible nested section' }],
- section: 'prepare-script',
- lineNumber: 3,
- },
- ],
-};
-
-export const collapsibleSectionOpened = {
- offset: 5,
- section_header: true,
- isHeader: true,
- isClosed: false,
- line: {
- content: [{ text: 'foo' }],
- section: 'prepare-script',
- lineNumber: 1,
- },
- section_duration: '00:03',
- lines: [
- {
- offset: 80,
- content: [{ text: 'this is a collapsible nested section' }],
- section: 'prepare-script',
- lineNumber: 3,
- },
- ],
-};
diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
deleted file mode 100644
index f2d249b6014..00000000000
--- a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
+++ /dev/null
@@ -1,240 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue';
-import eventHub from '~/jobs/components/table/event_hub';
-import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql';
-import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql';
-import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
-import JobCancelMutation from '~/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql';
-import {
- mockJobsNodes,
- mockJobsNodesAsGuest,
- playMutationResponse,
- retryMutationResponse,
- unscheduleMutationResponse,
- cancelMutationResponse,
-} from '../../../mock_data';
-
-jest.mock('~/lib/utils/url_utility');
-
-Vue.use(VueApollo);
-
-describe('Job actions cell', () => {
- let wrapper;
-
- const findMockJob = (jobName, nodes = mockJobsNodes) => {
- const job = nodes.find(({ name }) => name === jobName);
- expect(job).toBeDefined(); // ensure job is present
- return job;
- };
-
- const mockJob = findMockJob('build');
- const cancelableJob = findMockJob('cancelable');
- const playableJob = findMockJob('playable');
- const retryableJob = findMockJob('retryable');
- const failedJob = findMockJob('failed');
- const scheduledJob = findMockJob('scheduled');
- const jobWithArtifact = findMockJob('with_artifact');
- const cannotPlayJob = findMockJob('playable', mockJobsNodesAsGuest);
- const cannotRetryJob = findMockJob('retryable', mockJobsNodesAsGuest);
- const cannotPlayScheduledJob = findMockJob('scheduled', mockJobsNodesAsGuest);
-
- const findRetryButton = () => wrapper.findByTestId('retry');
- const findPlayButton = () => wrapper.findByTestId('play');
- const findCancelButton = () => wrapper.findByTestId('cancel-button');
- const findDownloadArtifactsButton = () => wrapper.findByTestId('download-artifacts');
- const findCountdownButton = () => wrapper.findByTestId('countdown');
- const findPlayScheduledJobButton = () => wrapper.findByTestId('play-scheduled');
- const findUnscheduleButton = () => wrapper.findByTestId('unschedule');
-
- const findModal = () => wrapper.findComponent(GlModal);
-
- const playMutationHandler = jest.fn().mockResolvedValue(playMutationResponse);
- const retryMutationHandler = jest.fn().mockResolvedValue(retryMutationResponse);
- const unscheduleMutationHandler = jest.fn().mockResolvedValue(unscheduleMutationResponse);
- const cancelMutationHandler = jest.fn().mockResolvedValue(cancelMutationResponse);
-
- const $toast = {
- show: jest.fn(),
- };
-
- const createMockApolloProvider = (requestHandlers) => {
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (job, requestHandlers, props = {}) => {
- wrapper = shallowMountExtended(ActionsCell, {
- propsData: {
- job,
- ...props,
- },
- apolloProvider: createMockApolloProvider(requestHandlers),
- mocks: {
- $toast,
- },
- });
- };
-
- it('displays the artifacts download button with correct link', () => {
- createComponent(jobWithArtifact);
-
- expect(findDownloadArtifactsButton().attributes('href')).toBe(
- jobWithArtifact.artifacts.nodes[0].downloadPath,
- );
- });
-
- it('does not display an artifacts download button', () => {
- createComponent(mockJob);
-
- expect(findDownloadArtifactsButton().exists()).toBe(false);
- });
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${cannotPlayJob}
- ${findRetryButton} | ${'retry'} | ${cannotRetryJob}
- ${findPlayScheduledJobButton} | ${'play scheduled'} | ${cannotPlayScheduledJob}
- `('does not display the $action button if user cannot update build', ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().exists()).toBe(false);
- });
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${playableJob}
- ${findRetryButton} | ${'retry'} | ${retryableJob}
- ${findDownloadArtifactsButton} | ${'download artifacts'} | ${jobWithArtifact}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob}
- `('displays the $action button', ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().exists()).toBe(true);
- });
-
- it.each`
- button | action | jobType | mutationFile | handler | jobId
- ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${playableJob.id}
- ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${retryableJob.id}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler} | ${cancelableJob.id}
- `('performs the $action mutation', ({ button, jobType, mutationFile, handler, jobId }) => {
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- expect(handler).toHaveBeenCalledWith({ id: jobId });
- });
-
- it.each`
- button | action | jobType | mutationFile | handler
- ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob} | ${JobUnscheduleMutation} | ${unscheduleMutationHandler}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler}
- `(
- 'the mutation action $action emits the jobActionPerformed event',
- async ({ button, jobType, mutationFile, handler }) => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('jobActionPerformed');
- expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
- },
- );
-
- it.each`
- button | action | jobType | mutationFile | handler | redirectLink
- ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${'/root/project/-/jobs/1986'}
- ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${'/root/project/-/jobs/1985'}
- `(
- 'the mutation action $action redirects to the job',
- async ({ button, jobType, mutationFile, handler, redirectLink }) => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(redirectTo).toHaveBeenCalledWith(redirectLink); // eslint-disable-line import/no-deprecated
- expect(eventHub.$emit).not.toHaveBeenCalled();
- },
- );
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${playableJob}
- ${findRetryButton} | ${'retry'} | ${retryableJob}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob}
- ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob}
- `('disables the $action button after first request', async ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().props('disabled')).toBe(false);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(button().props('disabled')).toBe(true);
- });
-
- describe('Retry button title', () => {
- it('displays retry title when job has failed and is retryable', () => {
- createComponent(failedJob);
-
- expect(findRetryButton().attributes('title')).toBe('Retry');
- });
-
- it('displays run again title when job has passed and is retryable', () => {
- createComponent(retryableJob);
-
- expect(findRetryButton().attributes('title')).toBe('Run again');
- });
- });
-
- describe('Scheduled Jobs', () => {
- const today = () => new Date('2021-08-31');
-
- beforeEach(() => {
- jest.spyOn(Date, 'now').mockImplementation(today);
- });
-
- it('displays the countdown, play and unschedule buttons', () => {
- createComponent(scheduledJob);
-
- expect(findCountdownButton().exists()).toBe(true);
- expect(findPlayScheduledJobButton().exists()).toBe(true);
- expect(findUnscheduleButton().exists()).toBe(true);
- });
-
- it('unschedules a job', () => {
- createComponent(scheduledJob, [[JobUnscheduleMutation, unscheduleMutationHandler]]);
-
- findUnscheduleButton().vm.$emit('click');
-
- expect(unscheduleMutationHandler).toHaveBeenCalledWith({
- id: scheduledJob.id,
- });
- });
-
- it('shows the play job confirmation modal', async () => {
- createComponent(scheduledJob);
-
- findPlayScheduledJobButton().vm.$emit('click');
-
- await nextTick();
-
- expect(findModal().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
deleted file mode 100644
index d015edb0e91..00000000000
--- a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import DurationCell from '~/jobs/components/table/cells/duration_cell.vue';
-
-describe('Duration Cell', () => {
- let wrapper;
-
- const findJobDuration = () => wrapper.findByTestId('job-duration');
- const findJobFinishedTime = () => wrapper.findByTestId('job-finished-time');
- const findDurationIcon = () => wrapper.findByTestId('duration-icon');
- const findFinishedTimeIcon = () => wrapper.findByTestId('finished-time-icon');
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(DurationCell, {
- propsData: {
- job: {
- ...props,
- },
- },
- }),
- );
- };
-
- it('does not display duration or finished time when no properties are present', () => {
- createComponent();
-
- expect(findJobDuration().exists()).toBe(false);
- expect(findJobFinishedTime().exists()).toBe(false);
- });
-
- it('displays duration and finished time when both properties are present', () => {
- const props = {
- duration: 7,
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findJobDuration().exists()).toBe(true);
- expect(findJobFinishedTime().exists()).toBe(true);
- });
-
- it('displays only the duration of the job when the duration property is present', () => {
- const props = {
- duration: 7,
- };
-
- createComponent(props);
-
- expect(findJobDuration().exists()).toBe(true);
- expect(findJobFinishedTime().exists()).toBe(false);
- });
-
- it('displays only the finished time of the job when the finshedAt property is present', () => {
- const props = {
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findJobFinishedTime().exists()).toBe(true);
- expect(findJobDuration().exists()).toBe(false);
- });
-
- it('displays icons for finished time and duration', () => {
- const props = {
- duration: 7,
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findFinishedTimeIcon().props('name')).toBe('calendar');
- expect(findDurationIcon().props('name')).toBe('timer');
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/job_cell_spec.js b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
deleted file mode 100644
index 73e37eed5f1..00000000000
--- a/spec/frontend/jobs/components/table/cells/job_cell_spec.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import JobCell from '~/jobs/components/table/cells/job_cell.vue';
-import { mockJobsNodes, mockJobsNodesAsGuest } from '../../../mock_data';
-
-describe('Job Cell', () => {
- let wrapper;
-
- const findMockJob = (jobName, nodes = mockJobsNodes) => {
- const job = nodes.find(({ name }) => name === jobName);
- expect(job).toBeDefined(); // ensure job is present
- return job;
- };
-
- const mockJob = findMockJob('build');
- const jobCreatedByTag = findMockJob('created_by_tag');
- const pendingJob = findMockJob('pending');
- const jobAsGuest = findMockJob('build', mockJobsNodesAsGuest);
-
- const findJobIdLink = () => wrapper.findByTestId('job-id-link');
- const findJobIdNoLink = () => wrapper.findByTestId('job-id-limited-access');
- const findJobRef = () => wrapper.findByTestId('job-ref');
- const findJobSha = () => wrapper.findByTestId('job-sha');
- const findLabelIcon = () => wrapper.findByTestId('label-icon');
- const findForkIcon = () => wrapper.findByTestId('fork-icon');
- const findStuckIcon = () => wrapper.findByTestId('stuck-icon');
- const findAllTagBadges = () => wrapper.findAllByTestId('job-tag-badge');
-
- const findBadgeById = (id) => wrapper.findByTestId(id);
-
- const createComponent = (job = mockJob) => {
- wrapper = extendedWrapper(
- shallowMount(JobCell, {
- propsData: {
- job,
- },
- }),
- );
- };
-
- describe('Job Id', () => {
- it('displays the job id and links to the job', () => {
- createComponent();
-
- const expectedJobId = `#${getIdFromGraphQLId(mockJob.id)}`;
-
- expect(findJobIdLink().text()).toBe(expectedJobId);
- expect(findJobIdLink().attributes('href')).toBe(mockJob.detailedStatus.detailsPath);
- expect(findJobIdNoLink().exists()).toBe(false);
- });
-
- it('display the job id with no link', () => {
- createComponent(jobAsGuest);
-
- const expectedJobId = `#${getIdFromGraphQLId(jobAsGuest.id)}`;
-
- expect(findJobIdNoLink().text()).toBe(expectedJobId);
- expect(findJobIdNoLink().exists()).toBe(true);
- expect(findJobIdLink().exists()).toBe(false);
- });
- });
-
- describe('Ref of the job', () => {
- it('displays the ref name and links to the ref', () => {
- createComponent();
-
- expect(findJobRef().text()).toBe(mockJob.refName);
- expect(findJobRef().attributes('href')).toBe(mockJob.refPath);
- });
-
- it('displays fork icon when job is not created by tag', () => {
- createComponent();
-
- expect(findForkIcon().exists()).toBe(true);
- expect(findLabelIcon().exists()).toBe(false);
- });
-
- it('displays label icon when job is created by a tag', () => {
- createComponent(jobCreatedByTag);
-
- expect(findLabelIcon().exists()).toBe(true);
- expect(findForkIcon().exists()).toBe(false);
- });
- });
-
- describe('Commit of the job', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the sha and links to the commit', () => {
- expect(findJobSha().text()).toBe(mockJob.shortSha);
- expect(findJobSha().attributes('href')).toBe(mockJob.commitPath);
- });
- });
-
- describe('Job badges', () => {
- it('displays tags of the job', () => {
- const mockJobWithTags = {
- tags: ['tag-1', 'tag-2', 'tag-3'],
- };
-
- createComponent(mockJobWithTags);
-
- expect(findAllTagBadges()).toHaveLength(mockJobWithTags.tags.length);
- });
-
- it.each`
- testId | text
- ${'manual-job-badge'} | ${'manual'}
- ${'triggered-job-badge'} | ${'triggered'}
- ${'fail-job-badge'} | ${'allowed to fail'}
- ${'delayed-job-badge'} | ${'delayed'}
- `('displays the static $text badge', ({ testId, text }) => {
- createComponent({
- manualJob: true,
- triggered: true,
- allowFailure: true,
- scheduledAt: '2021-03-09T14:58:50+00:00',
- });
-
- expect(findBadgeById(testId).exists()).toBe(true);
- expect(findBadgeById(testId).text()).toBe(text);
- });
- });
-
- describe('Job icons', () => {
- it('stuck icon is not shown if job is not stuck', () => {
- createComponent();
-
- expect(findStuckIcon().exists()).toBe(false);
- });
-
- it('stuck icon is shown if job is pending', () => {
- createComponent(pendingJob);
-
- expect(findStuckIcon().exists()).toBe(true);
- expect(findStuckIcon().attributes('name')).toBe('warning');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
deleted file mode 100644
index 3d424b20964..00000000000
--- a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { GlAvatar } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import PipelineCell from '~/jobs/components/table/cells/pipeline_cell.vue';
-
-const mockJobWithoutUser = {
- id: 'gid://gitlab/Ci::Build/2264',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/460',
- path: '/root/ci-project/-/pipelines/460',
- },
-};
-
-const mockJobWithUser = {
- id: 'gid://gitlab/Ci::Build/2264',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/460',
- path: '/root/ci-project/-/pipelines/460',
- user: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- webPath: '/root',
- },
- },
-};
-
-describe('Pipeline Cell', () => {
- let wrapper;
-
- const findPipelineId = () => wrapper.findByTestId('pipeline-id');
- const findPipelineUserLink = () => wrapper.findByTestId('pipeline-user-link');
- const findUserAvatar = () => wrapper.findComponent(GlAvatar);
-
- const createComponent = (props = mockJobWithUser) => {
- wrapper = extendedWrapper(
- shallowMount(PipelineCell, {
- propsData: {
- job: props,
- },
- }),
- );
- };
-
- describe('Pipeline Id', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the pipeline id and links to the pipeline', () => {
- const expectedPipelineId = `#${getIdFromGraphQLId(mockJobWithUser.pipeline.id)}`;
-
- expect(findPipelineId().text()).toBe(expectedPipelineId);
- expect(findPipelineId().attributes('href')).toBe(mockJobWithUser.pipeline.path);
- });
- });
-
- describe('Pipeline created by', () => {
- const apiWrapperText = 'API';
-
- it('shows and links to the pipeline user', () => {
- createComponent();
-
- expect(findPipelineUserLink().exists()).toBe(true);
- expect(findPipelineUserLink().attributes('href')).toBe(mockJobWithUser.pipeline.user.webPath);
- expect(findUserAvatar().attributes('src')).toBe(mockJobWithUser.pipeline.user.avatarUrl);
- expect(wrapper.text()).not.toContain(apiWrapperText);
- });
-
- it('shows pipeline was created by the API', () => {
- createComponent(mockJobWithoutUser);
-
- expect(findPipelineUserLink().exists()).toBe(false);
- expect(findUserAvatar().exists()).toBe(false);
- expect(wrapper.text()).toContain(apiWrapperText);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
deleted file mode 100644
index e3b1ca1cce3..00000000000
--- a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import cacheConfig from '~/jobs/components/table/graphql/cache_config';
-import {
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- CIJobConnectionIncomingCacheRunningStatus,
-} from '../../../mock_data';
-
-const firstLoadArgs = { first: 3, statuses: 'PENDING' };
-const runningArgs = { first: 3, statuses: 'RUNNING' };
-
-describe('jobs/components/table/graphql/cache_config', () => {
- describe('when fetching data with the same statuses', () => {
- it('should contain cache nodes and a status when merging caches on first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCache.nodes.length);
- expect(res.statuses).toBe('PENDING');
- });
-
- it('should add to existing caches when merging caches after first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(
- CIJobConnectionIncomingCache.nodes.length + CIJobConnectionExistingCache.nodes.length,
- );
- });
-
- it('should not add to existing cache if the incoming elements are the same', () => {
- // simulate that this is the last page
- const finalExistingCache = {
- ...CIJobConnectionExistingCache,
- pageInfo: {
- hasNextPage: false,
- },
- };
-
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- finalExistingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(CIJobConnectionExistingCache.nodes.length);
- });
-
- it('should contain the pageInfo key as part of the result', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.pageInfo).toEqual(
- expect.objectContaining({
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- }),
- );
- });
- });
-
- describe('when fetching data with different statuses', () => {
- it('should reset cache when a cache already exists', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCacheRunningStatus,
- {
- args: runningArgs,
- },
- );
-
- expect(res.nodes).not.toEqual(CIJobConnectionExistingCache.nodes);
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
- });
- });
-
- describe('when incoming data has no nodes', () => {
- it('should return existing cache', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- { __typename: 'CiJobConnection', count: 500 },
- {
- args: { statuses: 'SUCCESS' },
- },
- );
-
- const expectedResponse = {
- ...CIJobConnectionExistingCache,
- statuses: 'SUCCESS',
- };
-
- expect(res).toEqual(expectedResponse);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
deleted file mode 100644
index 032b83ca22b..00000000000
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ /dev/null
@@ -1,338 +0,0 @@
-import { GlAlert, GlEmptyState, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { s__ } from '~/locale';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { TEST_HOST } from 'spec/test_constants';
-import { createAlert } from '~/alert';
-import getJobsQuery from '~/jobs/components/table/graphql/queries/get_jobs.query.graphql';
-import getJobsCountQuery from '~/jobs/components/table/graphql/queries/get_jobs_count.query.graphql';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-import * as urlUtils from '~/lib/utils/url_utility';
-import {
- mockJobsResponsePaginated,
- mockJobsResponseEmpty,
- mockFailedSearchToken,
- mockJobsCountResponse,
-} from '../../mock_data';
-
-const projectPath = 'gitlab-org/gitlab';
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-
-describe('Job table app', () => {
- let wrapper;
-
- const successHandler = jest.fn().mockResolvedValue(mockJobsResponsePaginated);
- const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
- const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
-
- const countSuccessHandler = jest.fn().mockResolvedValue(mockJobsCountResponse);
-
- const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
- const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
- const findTable = () => wrapper.findComponent(JobsTable);
- const findTabs = () => wrapper.findComponent(JobsTableTabs);
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findFilteredSearch = () => wrapper.findComponent(JobsFilteredSearch);
-
- const triggerInfiniteScroll = () =>
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
-
- const createMockApolloProvider = (handler, countHandler) => {
- const requestHandlers = [
- [getJobsQuery, handler],
- [getJobsCountQuery, countHandler],
- ];
-
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = ({
- handler = successHandler,
- countHandler = countSuccessHandler,
- mountFn = shallowMount,
- } = {}) => {
- wrapper = mountFn(JobsTableApp, {
- provide: {
- fullPath: projectPath,
- },
- apolloProvider: createMockApolloProvider(handler, countHandler),
- });
- };
-
- describe('loading state', () => {
- it('should display skeleton loader when loading', () => {
- createComponent();
-
- expect(findSkeletonLoader().exists()).toBe(true);
- expect(findTable().exists()).toBe(false);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
-
- it('when switching tabs only the skeleton loader should show', () => {
- createComponent();
-
- findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(findSkeletonLoader().exists()).toBe(true);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
- });
-
- describe('loaded state', () => {
- beforeEach(async () => {
- createComponent();
-
- await waitForPromises();
- });
-
- it('should display the jobs table with data', () => {
- expect(findTable().exists()).toBe(true);
- expect(findSkeletonLoader().exists()).toBe(false);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
-
- it('should refetch jobs query on fetchJobsByStatus event', async () => {
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findTabs().vm.$emit('fetchJobsByStatus');
-
- expect(successHandler).toHaveBeenCalledTimes(2);
- });
-
- it('avoids refetch jobs query when scope has not changed', async () => {
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(successHandler).toHaveBeenCalledTimes(1);
- });
-
- it('should refetch jobs count query when the amount jobs and count do not match', async () => {
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- // after applying filter a new count is fetched
- findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(2);
-
- // tab is switched to `finished`, no count
- await findTabs().vm.$emit('fetchJobsByStatus', ['FAILED', 'SUCCESS', 'CANCELED']);
-
- // tab is switched back to `all`, the old filter count has to be overwritten with new count
- await findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(3);
- });
-
- describe('when infinite scrolling is triggered', () => {
- it('does not display a skeleton loader', () => {
- triggerInfiniteScroll();
-
- expect(findSkeletonLoader().exists()).toBe(false);
- });
-
- it('handles infinite scrolling by calling fetch more', async () => {
- triggerInfiniteScroll();
-
- await nextTick();
-
- const pageSize = 30;
-
- expect(findLoadingSpinner().exists()).toBe(true);
-
- await waitForPromises();
-
- expect(findLoadingSpinner().exists()).toBe(false);
-
- expect(successHandler).toHaveBeenLastCalledWith({
- first: pageSize,
- fullPath: projectPath,
- after: mockJobsResponsePaginated.data.project.jobs.pageInfo.endCursor,
- });
- });
- });
- });
-
- describe('error state', () => {
- it('should show an alert if there is an error fetching the jobs data', async () => {
- createComponent({ handler: failedHandler });
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe('There was an error fetching the jobs for your project.');
- expect(findTable().exists()).toBe(false);
- });
-
- it('should show an alert if there is an error fetching the jobs count data', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe(
- 'There was an error fetching the number of jobs for your project.',
- );
- });
-
- it('jobs table should still load if count query fails', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findTable().exists()).toBe(true);
- });
-
- it('jobs count should be zero if count query fails', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findTabs().props('allJobsCount')).toBe(0);
- });
- });
-
- describe('empty state', () => {
- it('should display empty state if there are no jobs and tab scope is null', async () => {
- createComponent({ handler: emptyHandler, mountFn: mount });
-
- await waitForPromises();
-
- expect(findEmptyState().exists()).toBe(true);
- expect(findTable().exists()).toBe(false);
- });
-
- it('should not display empty state if there are jobs and tab scope is not null', async () => {
- createComponent({ handler: successHandler, mountFn: mount });
-
- await waitForPromises();
-
- expect(findEmptyState().exists()).toBe(false);
- expect(findTable().exists()).toBe(true);
- });
- });
-
- describe('filtered search', () => {
- it('should display filtered search', () => {
- createComponent();
-
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- // this test should be updated once BE supports tab and filtered search filtering
- // https://gitlab.com/gitlab-org/gitlab/-/issues/356210
- it.each`
- scope | shouldDisplay
- ${null} | ${true}
- ${['FAILED', 'SUCCESS', 'CANCELED']} | ${false}
- `(
- 'with tab scope $scope the filtered search displays $shouldDisplay',
- async ({ scope, shouldDisplay }) => {
- createComponent();
-
- await waitForPromises();
-
- await findTabs().vm.$emit('fetchJobsByStatus', scope);
-
- expect(findFilteredSearch().exists()).toBe(shouldDisplay);
- },
- );
-
- it('refetches jobs query when filtering', async () => {
- createComponent();
-
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(successHandler).toHaveBeenCalledTimes(2);
- });
-
- it('refetches jobs count query when filtering', async () => {
- createComponent();
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(2);
- });
-
- it('shows raw text warning when user inputs raw text', async () => {
- const expectedWarning = {
- message: s__(
- 'Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens.',
- ),
- type: 'warning',
- };
-
- createComponent();
-
- expect(successHandler).toHaveBeenCalledTimes(1);
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', ['raw text']);
-
- expect(createAlert).toHaveBeenCalledWith(expectedWarning);
- expect(successHandler).toHaveBeenCalledTimes(1);
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
- });
-
- it('updates URL query string when filtering jobs by status', async () => {
- createComponent();
-
- jest.spyOn(urlUtils, 'updateHistory');
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/?statuses=FAILED`,
- });
- });
-
- it('resets query param after clearing tokens', () => {
- createComponent();
-
- jest.spyOn(urlUtils, 'updateHistory');
-
- findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(successHandler).toHaveBeenCalledWith({
- first: 30,
- fullPath: 'gitlab-org/gitlab',
- statuses: 'FAILED',
- });
- expect(countSuccessHandler).toHaveBeenCalledWith({
- fullPath: 'gitlab-org/gitlab',
- statuses: 'FAILED',
- });
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/?statuses=FAILED`,
- });
-
- findFilteredSearch().vm.$emit('filterJobsBySearch', []);
-
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/`,
- });
-
- expect(successHandler).toHaveBeenCalledWith({
- first: 30,
- fullPath: 'gitlab-org/gitlab',
- statuses: null,
- });
- expect(countSuccessHandler).toHaveBeenCalledWith({
- fullPath: 'gitlab-org/gitlab',
- statuses: null,
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js b/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js
deleted file mode 100644
index 05b066a9edc..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import JobsTableEmptyState from '~/jobs/components/table/jobs_table_empty_state.vue';
-
-describe('Jobs table empty state', () => {
- let wrapper;
-
- const pipelineEditorPath = '/root/project/-/ci/editor';
- const emptyStateSvgPath = 'assets/jobs-empty-state.svg';
-
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const createComponent = () => {
- wrapper = shallowMount(JobsTableEmptyState, {
- provide: {
- pipelineEditorPath,
- emptyStateSvgPath,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('displays empty state', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('links to the pipeline editor', () => {
- expect(findEmptyState().props('primaryButtonLink')).toBe(pipelineEditorPath);
- });
-
- it('shows an empty state image', () => {
- expect(findEmptyState().props('svgPath')).toBe(emptyStateSvgPath);
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js
deleted file mode 100644
index 654b6d1c130..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_spec.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { GlTable } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import { DEFAULT_FIELDS_ADMIN } from '~/pages/admin/jobs/components/constants';
-import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue';
-import RunnerCell from '~/pages/admin/jobs/components/table/cells/runner_cell.vue';
-import { mockJobsNodes, mockAllJobsNodes } from '../../mock_data';
-
-describe('Jobs Table', () => {
- let wrapper;
-
- const findTable = () => wrapper.findComponent(GlTable);
- const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
- const findTableRows = () => wrapper.findAllByTestId('jobs-table-row');
- const findJobStage = () => wrapper.findByTestId('job-stage-name');
- const findJobName = () => wrapper.findByTestId('job-name');
- const findJobProject = () => wrapper.findComponent(ProjectCell);
- const findJobRunner = () => wrapper.findComponent(RunnerCell);
- const findAllCoverageJobs = () => wrapper.findAllByTestId('job-coverage');
-
- const createComponent = (props = {}) => {
- wrapper = extendedWrapper(
- mount(JobsTable, {
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- describe('jobs table', () => {
- beforeEach(() => {
- createComponent({ jobs: mockJobsNodes });
- });
-
- it('displays the jobs table', () => {
- expect(findTable().exists()).toBe(true);
- });
-
- it('displays correct number of job rows', () => {
- expect(findTableRows()).toHaveLength(mockJobsNodes.length);
- });
-
- it('displays job status', () => {
- expect(findCiBadgeLink().exists()).toBe(true);
- });
-
- it('displays the job stage and name', () => {
- const [firstJob] = mockJobsNodes;
-
- expect(findJobStage().text()).toBe(firstJob.stage.name);
- expect(findJobName().text()).toBe(firstJob.name);
- });
-
- it('displays the coverage for only jobs that have coverage', () => {
- const jobsThatHaveCoverage = mockJobsNodes.filter((job) => job.coverage !== null);
-
- jobsThatHaveCoverage.forEach((job, index) => {
- expect(findAllCoverageJobs().at(index).text()).toBe(`${job.coverage}%`);
- });
- expect(findAllCoverageJobs()).toHaveLength(jobsThatHaveCoverage.length);
- });
- });
-
- describe('regular user', () => {
- beforeEach(() => {
- createComponent({ jobs: mockJobsNodes });
- });
-
- it('hides the job runner', () => {
- expect(findJobRunner().exists()).toBe(false);
- });
-
- it('hides the job project link', () => {
- expect(findJobProject().exists()).toBe(false);
- });
- });
-
- describe('admin mode', () => {
- beforeEach(() => {
- createComponent({ jobs: mockAllJobsNodes, tableFields: DEFAULT_FIELDS_ADMIN, admin: true });
- });
-
- it('displays the runner cell', () => {
- expect(findJobRunner().exists()).toBe(true);
- });
-
- it('displays the project cell', () => {
- expect(findJobProject().exists()).toBe(true);
- });
-
- it('displays correct number of job rows', () => {
- expect(findTableRows()).toHaveLength(mockAllJobsNodes.length);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
deleted file mode 100644
index d20a732508a..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { GlTab } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { trimText } from 'helpers/text_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-
-describe('Jobs Table Tabs', () => {
- let wrapper;
-
- const defaultProps = {
- allJobsCount: 286,
- loading: false,
- };
-
- const adminProps = {
- ...defaultProps,
- showCancelAllJobsButton: true,
- };
-
- const statuses = {
- success: 'SUCCESS',
- failed: 'FAILED',
- canceled: 'CANCELED',
- };
-
- const findAllTab = () => wrapper.findByTestId('jobs-all-tab');
- const findFinishedTab = () => wrapper.findByTestId('jobs-finished-tab');
- const findCancelJobsButton = () => wrapper.findAllComponents(CancelJobs);
-
- const triggerTabChange = (index) => wrapper.findAllComponents(GlTab).at(index).vm.$emit('click');
-
- const createComponent = (props = defaultProps) => {
- wrapper = extendedWrapper(
- mount(JobsTableTabs, {
- provide: {
- jobStatuses: {
- ...statuses,
- },
- },
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('displays All tab with count', () => {
- expect(trimText(findAllTab().text())).toBe(`All ${defaultProps.allJobsCount}`);
- });
-
- it('displays Finished tab with no count', () => {
- expect(findFinishedTab().text()).toBe('Finished');
- });
-
- it.each`
- tabIndex | expectedScope
- ${0} | ${null}
- ${1} | ${[statuses.success, statuses.failed, statuses.canceled]}
- `('emits fetchJobsByStatus with $expectedScope on tab change', ({ tabIndex, expectedScope }) => {
- triggerTabChange(tabIndex);
-
- expect(wrapper.emitted()).toEqual({ fetchJobsByStatus: [[expectedScope]] });
- });
-
- it('does not displays cancel all jobs button', () => {
- expect(findCancelJobsButton().exists()).toBe(false);
- });
-
- describe('admin mode', () => {
- it('displays cancel all jobs button', () => {
- createComponent(adminProps);
-
- expect(findCancelJobsButton().exists()).toBe(true);
- });
- });
-});