diff options
Diffstat (limited to 'spec/frontend/commit/commit_pipeline_status_component_spec.js')
-rw-r--r-- | spec/frontend/commit/commit_pipeline_status_component_spec.js | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js new file mode 100644 index 00000000000..1736d1d0df8 --- /dev/null +++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js @@ -0,0 +1,179 @@ +import Visibility from 'visibilityjs'; +import { GlLoadingIcon } from '@gitlab/ui'; +import Poll from '~/lib/utils/poll'; +import flash from '~/flash'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; +import { shallowMount } from '@vue/test-utils'; +import { getJSONFixture } from '../helpers/fixtures'; + +jest.mock('~/lib/utils/poll'); +jest.mock('visibilityjs'); +jest.mock('~/flash'); + +const mockFetchData = jest.fn(); +jest.mock('~/projects/tree/services/commit_pipeline_service', () => + jest.fn().mockImplementation(() => ({ + fetchData: mockFetchData.mockReturnValue(Promise.resolve()), + })), +); + +describe('Commit pipeline status component', () => { + let wrapper; + const { pipelines } = getJSONFixture('pipelines/pipelines.json'); + const { status: mockCiStatus } = pipelines[0].details; + + const defaultProps = { + endpoint: 'endpoint', + }; + + const createComponent = (props = {}) => { + wrapper = shallowMount(CommitPipelineStatus, { + propsData: { + ...defaultProps, + ...props, + }, + sync: false, + }); + }; + + const findLoader = () => wrapper.find(GlLoadingIcon); + const findLink = () => wrapper.find('a'); + const findCiIcon = () => findLink().find(CiIcon); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + jest.clearAllMocks(); + }); + + describe('Visibility management', () => { + describe('when component is hidden', () => { + beforeEach(() => { + Visibility.hidden.mockReturnValue(true); + createComponent(); + }); + + it('does not start polling', () => { + const [pollInstance] = Poll.mock.instances; + expect(pollInstance.makeRequest).not.toHaveBeenCalled(); + }); + + it('requests pipeline data', () => { + expect(mockFetchData).toHaveBeenCalled(); + }); + }); + + describe('when component is visible', () => { + beforeEach(() => { + Visibility.hidden.mockReturnValue(false); + createComponent(); + }); + + it('starts polling', () => { + const [pollInstance] = [...Poll.mock.instances].reverse(); + expect(pollInstance.makeRequest).toHaveBeenCalled(); + }); + }); + + describe('when component changes its visibility', () => { + it.each` + visibility | action + ${false} | ${'restart'} + ${true} | ${'stop'} + `( + '$action polling when component visibility becomes $visibility', + ({ visibility, action }) => { + Visibility.hidden.mockReturnValue(!visibility); + createComponent(); + const [pollInstance] = Poll.mock.instances; + expect(pollInstance[action]).not.toHaveBeenCalled(); + Visibility.hidden.mockReturnValue(visibility); + const [visibilityHandler] = Visibility.change.mock.calls[0]; + visibilityHandler(); + expect(pollInstance[action]).toHaveBeenCalled(); + }, + ); + }); + }); + + it('stops polling when component is destroyed', () => { + createComponent(); + wrapper.destroy(); + const [pollInstance] = Poll.mock.instances; + expect(pollInstance.stop).toHaveBeenCalled(); + }); + + describe('when polling', () => { + let pollConfig; + beforeEach(() => { + Poll.mockImplementation(config => { + pollConfig = config; + return { makeRequest: jest.fn(), restart: jest.fn(), stop: jest.fn() }; + }); + createComponent(); + }); + + it('shows the loading icon at start', () => { + createComponent(); + expect(findLoader().exists()).toBe(true); + + pollConfig.successCallback({ + data: { pipelines: [] }, + }); + + return wrapper.vm.$nextTick().then(() => { + expect(findLoader().exists()).toBe(false); + }); + }); + + describe('is successful', () => { + beforeEach(() => { + pollConfig.successCallback({ + data: { pipelines: [{ details: { status: mockCiStatus } }] }, + }); + return wrapper.vm.$nextTick(); + }); + + it('does not render loader', () => { + expect(findLoader().exists()).toBe(false); + }); + + it('renders link with href', () => { + expect(findLink().attributes('href')).toEqual(mockCiStatus.details_path); + }); + + it('renders CI icon', () => { + expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: pending'); + expect(findCiIcon().props('status')).toEqual(mockCiStatus); + }); + }); + + describe('is not successful', () => { + beforeEach(() => { + pollConfig.errorCallback(); + }); + + it('does not render loader', () => { + expect(findLoader().exists()).toBe(false); + }); + + it('renders link with href', () => { + expect(findLink().attributes('href')).toBeUndefined(); + }); + + it('renders not found CI icon', () => { + expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: not found'); + expect(findCiIcon().props('status')).toEqual({ + text: 'not found', + icon: 'status_notfound', + group: 'notfound', + }); + }); + + it('displays flash error message', () => { + expect(flash).toHaveBeenCalled(); + }); + }); + }); +}); |