summaryrefslogtreecommitdiff
path: root/spec/frontend/jobs
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/jobs')
-rw-r--r--spec/frontend/jobs/bridge/app_spec.js123
-rw-r--r--spec/frontend/jobs/bridge/components/empty_state_spec.js7
-rw-r--r--spec/frontend/jobs/bridge/components/sidebar_spec.js97
-rw-r--r--spec/frontend/jobs/bridge/mock_data.js101
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js2
5 files changed, 284 insertions, 46 deletions
diff --git a/spec/frontend/jobs/bridge/app_spec.js b/spec/frontend/jobs/bridge/app_spec.js
index 0e232ab240d..c0faab90552 100644
--- a/spec/frontend/jobs/bridge/app_spec.js
+++ b/spec/frontend/jobs/bridge/app_spec.js
@@ -1,27 +1,104 @@
-import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import getPipelineQuery from '~/jobs/bridge/graphql/queries/pipeline.query.graphql';
+import waitForPromises from 'helpers/wait_for_promises';
import BridgeApp from '~/jobs/bridge/app.vue';
import BridgeEmptyState from '~/jobs/bridge/components/empty_state.vue';
import BridgeSidebar from '~/jobs/bridge/components/sidebar.vue';
+import CiHeader from '~/vue_shared/components/header_ci_component.vue';
+import {
+ MOCK_BUILD_ID,
+ MOCK_PIPELINE_IID,
+ MOCK_PROJECT_FULL_PATH,
+ mockPipelineQueryResponse,
+} from './mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
describe('Bridge Show Page', () => {
let wrapper;
+ let mockApollo;
+ let mockPipelineQuery;
+
+ const createComponent = (options) => {
+ wrapper = shallowMount(BridgeApp, {
+ provide: {
+ buildId: MOCK_BUILD_ID,
+ projectFullPath: MOCK_PROJECT_FULL_PATH,
+ pipelineIid: MOCK_PIPELINE_IID,
+ },
+ mocks: {
+ $apollo: {
+ queries: {
+ pipeline: {
+ loading: true,
+ },
+ },
+ },
+ },
+ ...options,
+ });
+ };
- const createComponent = () => {
- wrapper = shallowMount(BridgeApp, {});
+ const createComponentWithApollo = () => {
+ const handlers = [[getPipelineQuery, mockPipelineQuery]];
+ mockApollo = createMockApollo(handlers);
+
+ createComponent({
+ localVue,
+ apolloProvider: mockApollo,
+ mocks: {},
+ });
};
+ const findCiHeader = () => wrapper.findComponent(CiHeader);
const findEmptyState = () => wrapper.findComponent(BridgeEmptyState);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findSidebar = () => wrapper.findComponent(BridgeSidebar);
+ beforeEach(() => {
+ mockPipelineQuery = jest.fn();
+ });
+
afterEach(() => {
+ mockPipelineQuery.mockReset();
wrapper.destroy();
});
- describe('template', () => {
+ describe('while pipeline query is loading', () => {
beforeEach(() => {
createComponent();
});
+ it('renders loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('after pipeline query is loaded', () => {
+ beforeEach(() => {
+ mockPipelineQuery.mockResolvedValue(mockPipelineQueryResponse);
+ createComponentWithApollo();
+ waitForPromises();
+ });
+
+ it('query is called with correct variables', async () => {
+ expect(mockPipelineQuery).toHaveBeenCalledTimes(1);
+ expect(mockPipelineQuery).toHaveBeenCalledWith({
+ fullPath: MOCK_PROJECT_FULL_PATH,
+ iid: MOCK_PIPELINE_IID,
+ });
+ });
+
+ it('renders CI header state', () => {
+ expect(findCiHeader().exists()).toBe(true);
+ });
+
it('renders empty state', () => {
expect(findEmptyState().exists()).toBe(true);
});
@@ -30,4 +107,42 @@ describe('Bridge Show Page', () => {
expect(findSidebar().exists()).toBe(true);
});
});
+
+ describe('sidebar expansion', () => {
+ beforeEach(() => {
+ mockPipelineQuery.mockResolvedValue(mockPipelineQueryResponse);
+ createComponentWithApollo();
+ waitForPromises();
+ });
+
+ describe('on resize', () => {
+ it.each`
+ breakpoint | isSidebarExpanded
+ ${'xs'} | ${false}
+ ${'sm'} | ${false}
+ ${'md'} | ${true}
+ ${'lg'} | ${true}
+ ${'xl'} | ${true}
+ `(
+ 'sets isSidebarExpanded to `$isSidebarExpanded` when the breakpoint is "$breakpoint"',
+ async ({ breakpoint, isSidebarExpanded }) => {
+ jest.spyOn(GlBreakpointInstance, 'getBreakpointSize').mockReturnValue(breakpoint);
+
+ window.dispatchEvent(new Event('resize'));
+ await nextTick();
+
+ expect(findSidebar().exists()).toBe(isSidebarExpanded);
+ },
+ );
+ });
+
+ it('toggles expansion on button click', async () => {
+ expect(findSidebar().exists()).toBe(true);
+
+ wrapper.vm.toggleSidebar();
+ await nextTick();
+
+ expect(findSidebar().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/jobs/bridge/components/empty_state_spec.js b/spec/frontend/jobs/bridge/components/empty_state_spec.js
index 83642450118..38c55b296f0 100644
--- a/spec/frontend/jobs/bridge/components/empty_state_spec.js
+++ b/spec/frontend/jobs/bridge/components/empty_state_spec.js
@@ -6,14 +6,13 @@ import { MOCK_EMPTY_ILLUSTRATION_PATH, MOCK_PATH_TO_DOWNSTREAM } from '../mock_d
describe('Bridge Empty State', () => {
let wrapper;
- const createComponent = (props) => {
+ const createComponent = ({ downstreamPipelinePath }) => {
wrapper = shallowMount(BridgeEmptyState, {
provide: {
emptyStateIllustrationPath: MOCK_EMPTY_ILLUSTRATION_PATH,
},
propsData: {
- downstreamPipelinePath: MOCK_PATH_TO_DOWNSTREAM,
- ...props,
+ downstreamPipelinePath,
},
});
};
@@ -28,7 +27,7 @@ describe('Bridge Empty State', () => {
describe('template', () => {
beforeEach(() => {
- createComponent();
+ createComponent({ downstreamPipelinePath: MOCK_PATH_TO_DOWNSTREAM });
});
it('renders illustration', () => {
diff --git a/spec/frontend/jobs/bridge/components/sidebar_spec.js b/spec/frontend/jobs/bridge/components/sidebar_spec.js
index ba4018753af..5006d4f08a6 100644
--- a/spec/frontend/jobs/bridge/components/sidebar_spec.js
+++ b/spec/frontend/jobs/bridge/components/sidebar_spec.js
@@ -1,24 +1,38 @@
import { GlButton, GlDropdown } from '@gitlab/ui';
-import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
-import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils';
import BridgeSidebar from '~/jobs/bridge/components/sidebar.vue';
-import { BUILD_NAME } from '../mock_data';
+import CommitBlock from '~/jobs/components/commit_block.vue';
+import { mockCommit, mockJob } from '../mock_data';
describe('Bridge Sidebar', () => {
let wrapper;
- const createComponent = () => {
+ const MockHeaderEl = {
+ getBoundingClientRect() {
+ return {
+ bottom: '40',
+ };
+ },
+ };
+
+ const createComponent = ({ featureFlag } = {}) => {
wrapper = shallowMount(BridgeSidebar, {
provide: {
- buildName: BUILD_NAME,
+ glFeatures: {
+ triggerJobRetryAction: featureFlag,
+ },
+ },
+ propsData: {
+ bridgeJob: mockJob,
+ commit: mockCommit,
},
});
};
- const findSidebar = () => wrapper.find('aside');
+ const findJobTitle = () => wrapper.find('h4');
+ const findCommitBlock = () => wrapper.findComponent(CommitBlock);
const findRetryDropdown = () => wrapper.find(GlDropdown);
- const findToggle = () => wrapper.find(GlButton);
+ const findToggleBtn = () => wrapper.findComponent(GlButton);
afterEach(() => {
wrapper.destroy();
@@ -29,8 +43,23 @@ describe('Bridge Sidebar', () => {
createComponent();
});
- it('renders retry dropdown', () => {
- expect(findRetryDropdown().exists()).toBe(true);
+ it('renders job name', () => {
+ expect(findJobTitle().text()).toBe(mockJob.name);
+ });
+
+ it('renders commit information', () => {
+ expect(findCommitBlock().exists()).toBe(true);
+ });
+ });
+
+ describe('styles', () => {
+ beforeEach(async () => {
+ jest.spyOn(document, 'querySelector').mockReturnValue(MockHeaderEl);
+ createComponent();
+ });
+
+ it('calculates root styles correctly', () => {
+ expect(wrapper.attributes('style')).toBe('width: 290px; top: 40px;');
});
});
@@ -39,38 +68,32 @@ describe('Bridge Sidebar', () => {
createComponent();
});
- it('toggles expansion on button click', async () => {
- expect(findSidebar().classes()).not.toContain('gl-display-none');
+ it('emits toggle sidebar event on button click', async () => {
+ expect(wrapper.emitted('toggleSidebar')).toBe(undefined);
- findToggle().vm.$emit('click');
- await nextTick();
+ findToggleBtn().vm.$emit('click');
- expect(findSidebar().classes()).toContain('gl-display-none');
+ expect(wrapper.emitted('toggleSidebar')).toHaveLength(1);
});
+ });
- describe('on resize', () => {
- it.each`
- breakpoint | isSidebarExpanded
- ${'xs'} | ${false}
- ${'sm'} | ${false}
- ${'md'} | ${true}
- ${'lg'} | ${true}
- ${'xl'} | ${true}
- `(
- 'sets isSidebarExpanded to `$isSidebarExpanded` when the breakpoint is "$breakpoint"',
- async ({ breakpoint, isSidebarExpanded }) => {
- jest.spyOn(GlBreakpointInstance, 'getBreakpointSize').mockReturnValue(breakpoint);
-
- window.dispatchEvent(new Event('resize'));
- await nextTick();
-
- if (isSidebarExpanded) {
- expect(findSidebar().classes()).not.toContain('gl-display-none');
- } else {
- expect(findSidebar().classes()).toContain('gl-display-none');
- }
- },
- );
+ describe('retry action', () => {
+ describe('when feature flag is ON', () => {
+ beforeEach(() => {
+ createComponent({ featureFlag: true });
+ });
+
+ it('renders retry dropdown', () => {
+ expect(findRetryDropdown().exists()).toBe(true);
+ });
+ });
+
+ describe('when feature flag is OFF', () => {
+ it('does not render retry dropdown', () => {
+ createComponent({ featureFlag: false });
+
+ expect(findRetryDropdown().exists()).toBe(false);
+ });
});
});
});
diff --git a/spec/frontend/jobs/bridge/mock_data.js b/spec/frontend/jobs/bridge/mock_data.js
index 146d1a062ac..4084bb54163 100644
--- a/spec/frontend/jobs/bridge/mock_data.js
+++ b/spec/frontend/jobs/bridge/mock_data.js
@@ -1,3 +1,102 @@
export const MOCK_EMPTY_ILLUSTRATION_PATH = '/path/to/svg';
export const MOCK_PATH_TO_DOWNSTREAM = '/path/to/downstream/pipeline';
-export const BUILD_NAME = 'Child Pipeline Trigger';
+export const MOCK_BUILD_ID = '1331';
+export const MOCK_PIPELINE_IID = '174';
+export const MOCK_PROJECT_FULL_PATH = '/root/project/';
+export const MOCK_SHA = '38f3d89147765427a7ce58be28cd76d14efa682a';
+
+export const mockCommit = {
+ id: `gid://gitlab/CommitPresenter/${MOCK_SHA}`,
+ shortId: '38f3d891',
+ title: 'Update .gitlab-ci.yml file',
+ webPath: `/root/project/-/commit/${MOCK_SHA}`,
+ __typename: 'Commit',
+};
+
+export const mockJob = {
+ createdAt: '2021-12-10T09:05:45Z',
+ id: 'gid://gitlab/Ci::Build/1331',
+ name: 'triggerJobName',
+ scheduledAt: null,
+ startedAt: '2021-12-10T09:13:43Z',
+ status: 'SUCCESS',
+ triggered: null,
+ detailedStatus: {
+ id: '1',
+ detailsPath: '/root/project/-/jobs/1331',
+ icon: 'status_success',
+ group: 'success',
+ text: 'passed',
+ tooltip: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ downstreamPipeline: {
+ id: '1',
+ path: '/root/project/-/pipelines/175',
+ },
+ stage: {
+ id: '1',
+ name: 'build',
+ __typename: 'CiStage',
+ },
+ __typename: 'CiJob',
+};
+
+export const mockUser = {
+ id: 'gid://gitlab/User/1',
+ avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ name: 'Administrator',
+ username: 'root',
+ webPath: '/root',
+ webUrl: 'http://gdk.test:3000/root',
+ status: {
+ message: 'making great things',
+ __typename: 'UserStatus',
+ },
+ __typename: 'UserCore',
+};
+
+export const mockStage = {
+ id: '1',
+ name: 'build',
+ jobs: {
+ nodes: [mockJob],
+ __typename: 'CiJobConnection',
+ },
+ __typename: 'CiStage',
+};
+
+export const mockPipelineQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ commit: mockCommit,
+ id: 'gid://gitlab/Ci::Pipeline/174',
+ iid: '88',
+ path: '/root/project/-/pipelines/174',
+ sha: MOCK_SHA,
+ ref: 'main',
+ refPath: 'path/to/ref',
+ user: mockUser,
+ detailedStatus: {
+ id: '1',
+ icon: 'status_failed',
+ group: 'failed',
+ __typename: 'DetailedStatus',
+ },
+ stages: {
+ edges: [
+ {
+ node: mockStage,
+ __typename: 'CiStageEdge',
+ },
+ ],
+ __typename: 'CiStageConnection',
+ },
+ __typename: 'Pipeline',
+ },
+ __typename: 'Project',
+ },
+ },
+};
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
index 482d0df4e9a..05988eecb10 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -114,6 +114,8 @@ describe('Job table app', () => {
await wrapper.vm.$nextTick();
+ // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // eslint-disable-next-line no-restricted-syntax
wrapper.setData({
jobs: {
pageInfo: {