summaryrefslogtreecommitdiff
path: root/spec/frontend/ci_lint
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ci_lint')
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_results_spec.js114
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_spec.js77
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_warnings_spec.js54
-rw-r--r--spec/frontend/ci_lint/mock_data.js49
4 files changed, 294 insertions, 0 deletions
diff --git a/spec/frontend/ci_lint/components/ci_lint_results_spec.js b/spec/frontend/ci_lint/components/ci_lint_results_spec.js
new file mode 100644
index 00000000000..37575a988c5
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_results_spec.js
@@ -0,0 +1,114 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import { GlTable } from '@gitlab/ui';
+import CiLintResults from '~/ci_lint/components/ci_lint_results.vue';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { mockJobs, mockErrors, mockWarnings } from '../mock_data';
+
+describe('CI Lint Results', () => {
+ let wrapper;
+
+ const createComponent = (props = {}, mountFn = shallowMount) => {
+ wrapper = mountFn(CiLintResults, {
+ propsData: {
+ valid: true,
+ jobs: mockJobs,
+ errors: [],
+ warnings: [],
+ dryRun: false,
+ ...props,
+ },
+ });
+ };
+
+ const findTable = () => wrapper.find(GlTable);
+ const findByTestId = selector => () => wrapper.find(`[data-testid="ci-lint-${selector}"]`);
+ const findAllByTestId = selector => () => wrapper.findAll(`[data-testid="ci-lint-${selector}"]`);
+ const findErrors = findByTestId('errors');
+ const findWarnings = findByTestId('warnings');
+ const findStatus = findByTestId('status');
+ const findOnlyExcept = findByTestId('only-except');
+ const findLintParameters = findAllByTestId('parameter');
+ const findBeforeScripts = findAllByTestId('before-script');
+ const findScripts = findAllByTestId('script');
+ const findAfterScripts = findAllByTestId('after-script');
+ const filterEmptyScripts = property => mockJobs.filter(job => job[property].length !== 0);
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('Invalid results', () => {
+ beforeEach(() => {
+ createComponent({ valid: false, errors: mockErrors, warnings: mockWarnings }, mount);
+ });
+
+ it('does not display the table', () => {
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('displays the invalid status', () => {
+ expect(findStatus().text()).toBe(`Status: ${wrapper.vm.$options.incorrect.text}`);
+ expect(findStatus().props('variant')).toBe(wrapper.vm.$options.incorrect.variant);
+ });
+
+ it('displays the error message', () => {
+ const [expectedError] = mockErrors;
+
+ expect(findErrors().text()).toBe(expectedError);
+ });
+
+ it('displays the warning message', () => {
+ const [expectedWarning] = mockWarnings;
+
+ expect(findWarnings().exists()).toBe(true);
+ expect(findWarnings().text()).toContain(expectedWarning);
+ });
+ });
+
+ describe('Valid results', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('displays the valid status', () => {
+ expect(findStatus().text()).toBe(wrapper.vm.$options.correct.text);
+ expect(findStatus().props('variant')).toBe(wrapper.vm.$options.correct.variant);
+ });
+
+ it('does not display only/expect values with dry run', () => {
+ expect(findOnlyExcept().exists()).toBe(false);
+ });
+ });
+
+ describe('Lint results', () => {
+ beforeEach(() => {
+ createComponent({}, mount);
+ });
+
+ it('formats parameter value', () => {
+ findLintParameters().wrappers.forEach((job, index) => {
+ const { stage } = mockJobs[index];
+ const { name } = mockJobs[index];
+
+ expect(job.text()).toBe(`${capitalizeFirstCharacter(stage)} Job - ${name}`);
+ });
+ });
+
+ it('only shows before scripts when data is present', () => {
+ expect(findBeforeScripts()).toHaveLength(filterEmptyScripts('beforeScript').length);
+ });
+
+ it('only shows script when data is present', () => {
+ expect(findScripts()).toHaveLength(filterEmptyScripts('script').length);
+ });
+
+ it('only shows after script when data is present', () => {
+ expect(findAfterScripts()).toHaveLength(filterEmptyScripts('afterScript').length);
+ });
+ });
+});
diff --git a/spec/frontend/ci_lint/components/ci_lint_spec.js b/spec/frontend/ci_lint/components/ci_lint_spec.js
new file mode 100644
index 00000000000..e617cca499d
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount } from '@vue/test-utils';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
+import CiLint from '~/ci_lint/components/ci_lint.vue';
+import lintCIMutation from '~/ci_lint/graphql/mutations/lint_ci.mutation.graphql';
+
+describe('CI Lint', () => {
+ let wrapper;
+
+ const endpoint = '/namespace/project/-/ci/lint';
+ const content =
+ "test_job:\n stage: build\n script: echo 'Building'\n only:\n - web\n - chat\n - pushes\n allow_failure: true ";
+
+ const createComponent = () => {
+ wrapper = shallowMount(CiLint, {
+ data() {
+ return {
+ content,
+ };
+ },
+ propsData: {
+ endpoint,
+ helpPagePath: '/help/ci/lint#pipeline-simulation',
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ },
+ });
+ };
+
+ const findEditor = () => wrapper.find(EditorLite);
+ const findValidateBtn = () => wrapper.find('[data-testid="ci-lint-validate"]');
+ const findClearBtn = () => wrapper.find('[data-testid="ci-lint-clear"]');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays the editor', () => {
+ expect(findEditor().exists()).toBe(true);
+ });
+
+ it('validate action calls mutation correctly', () => {
+ findValidateBtn().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: lintCIMutation,
+ variables: { content, dry: false, endpoint },
+ });
+ });
+
+ it('validate action calls mutation with dry run', async () => {
+ const dryRunEnabled = true;
+
+ await wrapper.setData({ dryRun: dryRunEnabled });
+
+ findValidateBtn().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: lintCIMutation,
+ variables: { content, dry: dryRunEnabled, endpoint },
+ });
+ });
+
+ it('content is cleared on clear action', async () => {
+ expect(findEditor().props('value')).toBe(content);
+
+ await findClearBtn().vm.$emit('click');
+
+ expect(findEditor().props('value')).toBe('');
+ });
+});
diff --git a/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js b/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js
new file mode 100644
index 00000000000..6e0a4881e14
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js
@@ -0,0 +1,54 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { trimText } from 'helpers/text_helper';
+import CiLintWarnings from '~/ci_lint/components/ci_lint_warnings.vue';
+
+const warnings = ['warning 1', 'warning 2', 'warning 3'];
+
+describe('CI lint warnings', () => {
+ let wrapper;
+
+ const createComponent = (limit = 25) => {
+ wrapper = mount(CiLintWarnings, {
+ propsData: {
+ warnings,
+ maxWarnings: limit,
+ },
+ });
+ };
+
+ const findWarningAlert = () => wrapper.find(GlAlert);
+ const findWarnings = () => wrapper.findAll('[data-testid="ci-lint-warning"]');
+ const findWarningMessage = () => trimText(wrapper.find(GlSprintf).text());
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('displays the warning alert', () => {
+ createComponent();
+
+ expect(findWarningAlert().exists()).toBe(true);
+ });
+
+ it('displays all the warnings', () => {
+ createComponent();
+
+ expect(findWarnings()).toHaveLength(warnings.length);
+ });
+
+ it('shows the correct message when the limit is not passed', () => {
+ createComponent();
+
+ expect(findWarningMessage()).toBe(`${warnings.length} warnings found:`);
+ });
+
+ it('shows the correct message when the limit is passed', () => {
+ const limit = 2;
+
+ createComponent(limit);
+
+ expect(findWarningMessage()).toBe(`${warnings.length} warnings found: showing first ${limit}`);
+ });
+});
diff --git a/spec/frontend/ci_lint/mock_data.js b/spec/frontend/ci_lint/mock_data.js
new file mode 100644
index 00000000000..cf7d69dcad3
--- /dev/null
+++ b/spec/frontend/ci_lint/mock_data.js
@@ -0,0 +1,49 @@
+export const mockJobs = [
+ {
+ name: 'job_1',
+ stage: 'build',
+ beforeScript: [],
+ script: ["echo 'Building'"],
+ afterScript: [],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: true,
+ only: { refs: ['web', 'chat', 'pushes'] },
+ except: null,
+ },
+ {
+ name: 'multi_project_job',
+ stage: 'test',
+ beforeScript: [],
+ script: [],
+ afterScript: [],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: false,
+ only: { refs: ['branches', 'tags'] },
+ except: null,
+ },
+ {
+ name: 'job_2',
+ stage: 'test',
+ beforeScript: ["echo 'before script'"],
+ script: ["echo 'script'"],
+ afterScript: ["echo 'after script"],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: false,
+ only: { refs: ['branches@gitlab-org/gitlab'] },
+ except: { refs: ['master@gitlab-org/gitlab', '/^release/.*$/@gitlab-org/gitlab'] },
+ },
+];
+
+export const mockErrors = [
+ '"job_1 job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post"',
+];
+
+export const mockWarnings = [
+ '"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"',
+];