diff options
Diffstat (limited to 'spec/frontend/ide/components/jobs')
5 files changed, 103 insertions, 193 deletions
diff --git a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap b/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap deleted file mode 100644 index 45444166a50..00000000000 --- a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap +++ /dev/null @@ -1,60 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`IDE pipeline stage renders stage details & icon 1`] = ` -<div - class="ide-stage card gl-mt-3" -> - <div - class="card-header" - > - <ci-icon-stub - cssclasses="" - size="24" - status="[object Object]" - /> - - <strong - class="gl-ml-3 text-truncate" - data-container="body" - > - - build - - </strong> - - <div - class="gl-mr-3 gl-ml-2" - > - <gl-badge-stub - size="md" - variant="muted" - > - 4 - </gl-badge-stub> - </div> - - <gl-icon-stub - class="ide-stage-collapse-icon" - name="chevron-lg-down" - size="16" - /> - </div> - - <div - class="card-body p-0" - > - <item-stub - job="[object Object]" - /> - <item-stub - job="[object Object]" - /> - <item-stub - job="[object Object]" - /> - <item-stub - job="[object Object]" - /> - </div> -</div> -`; diff --git a/spec/frontend/ide/components/jobs/detail/description_spec.js b/spec/frontend/ide/components/jobs/detail/description_spec.js index 128ccff6568..629c4424314 100644 --- a/spec/frontend/ide/components/jobs/detail/description_spec.js +++ b/spec/frontend/ide/components/jobs/detail/description_spec.js @@ -1,44 +1,43 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; +import { mount } from '@vue/test-utils'; +import { GlIcon } from '@gitlab/ui'; import Description from '~/ide/components/jobs/detail/description.vue'; import { jobs } from '../../../mock_data'; describe('IDE job description', () => { - const Component = Vue.extend(Description); - let vm; + let wrapper; beforeEach(() => { - vm = mountComponent(Component, { - job: jobs[0], + wrapper = mount(Description, { + propsData: { + job: jobs[0], + }, }); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders job details', () => { - expect(vm.$el.textContent).toContain('#1'); - expect(vm.$el.textContent).toContain('test'); + expect(wrapper.text()).toContain('#1'); + expect(wrapper.text()).toContain('test'); }); it('renders CI icon', () => { - expect( - vm.$el.querySelector('.ci-status-icon [data-testid="status_success_borderless-icon"]'), - ).not.toBe(null); + expect(wrapper.find('.ci-status-icon').findComponent(GlIcon).exists()).toBe(true); }); it('renders a borderless CI icon', () => { - expect( - vm.$el.querySelector('.borderless [data-testid="status_success_borderless-icon"]'), - ).not.toBe(null); + expect(wrapper.find('.borderless').findComponent(GlIcon).exists()).toBe(true); }); it('renders bridge job details without the job link', () => { - vm = mountComponent(Component, { - job: { ...jobs[0], path: undefined }, + wrapper = mount(Description, { + propsData: { + job: { ...jobs[0], path: undefined }, + }, }); - expect(vm.$el.querySelector('[data-testid="description-detail-link"]')).toBe(null); + expect(wrapper.find('[data-testid="description-detail-link"]').exists()).toBe(false); }); }); diff --git a/spec/frontend/ide/components/jobs/detail_spec.js b/spec/frontend/ide/components/jobs/detail_spec.js index 9122471d421..bf2be3aa595 100644 --- a/spec/frontend/ide/components/jobs/detail_spec.js +++ b/spec/frontend/ide/components/jobs/detail_spec.js @@ -1,15 +1,17 @@ -import Vue, { nextTick } from 'vue'; +import { nextTick } from 'vue'; +import { mount } from '@vue/test-utils'; + import { TEST_HOST } from 'helpers/test_constants'; -import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; import JobDetail from '~/ide/components/jobs/detail.vue'; import { createStore } from '~/ide/stores'; import { jobs } from '../../mock_data'; describe('IDE jobs detail view', () => { - let vm; + let wrapper; + let store; const createComponent = () => { - const store = createStore(); + store = createStore(); store.state.pipelines.detailJob = { ...jobs[0], @@ -18,163 +20,129 @@ describe('IDE jobs detail view', () => { rawPath: `${TEST_HOST}/raw`, }; - return createComponentWithStore(Vue.extend(JobDetail), store); + jest.spyOn(store, 'dispatch'); + store.dispatch.mockResolvedValue(); + + wrapper = mount(JobDetail, { store }); }; - beforeEach(() => { - vm = createComponent(); + const findBuildJobLog = () => wrapper.find('pre'); + const findScrollToBottomButton = () => wrapper.find('button[aria-label="Scroll to bottom"]'); + const findScrollToTopButton = () => wrapper.find('button[aria-label="Scroll to top"]'); - jest.spyOn(vm, 'fetchJobLogs').mockResolvedValue(); + beforeEach(() => { + createComponent(); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); describe('mounted', () => { - beforeEach(() => { - vm = vm.$mount(); - }); + const findJobOutput = () => wrapper.find('.bash'); + const findBuildLoaderAnimation = () => wrapper.find('.build-loader-animation'); it('calls fetchJobLogs', () => { - expect(vm.fetchJobLogs).toHaveBeenCalled(); + expect(store.dispatch).toHaveBeenCalledWith('pipelines/fetchJobLogs', undefined); }); it('scrolls to bottom', () => { - expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalled(); + expect(findBuildJobLog().element.scrollTo).toHaveBeenCalled(); }); it('renders job output', () => { - expect(vm.$el.querySelector('.bash').textContent).toContain('testing'); + expect(findJobOutput().text()).toContain('testing'); }); it('renders empty message output', async () => { - vm.$store.state.pipelines.detailJob.output = ''; - + store.state.pipelines.detailJob.output = ''; await nextTick(); - expect(vm.$el.querySelector('.bash').textContent).toContain('No messages were logged'); + + expect(findJobOutput().text()).toContain('No messages were logged'); }); it('renders loading icon', () => { - expect(vm.$el.querySelector('.build-loader-animation')).not.toBe(null); - expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe(''); + expect(findBuildLoaderAnimation().exists()).toBe(true); + expect(findBuildLoaderAnimation().isVisible()).toBe(true); }); it('hides output when loading', () => { - expect(vm.$el.querySelector('.bash')).not.toBe(null); - expect(vm.$el.querySelector('.bash').style.display).toBe('none'); + expect(findJobOutput().exists()).toBe(true); + expect(findJobOutput().isVisible()).toBe(false); }); it('hide loading icon when isLoading is false', async () => { - vm.$store.state.pipelines.detailJob.isLoading = false; - + store.state.pipelines.detailJob.isLoading = false; await nextTick(); - expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('none'); - }); - it('resets detailJob when clicking header button', () => { - jest.spyOn(vm, 'setDetailJob').mockImplementation(); + expect(findBuildLoaderAnimation().isVisible()).toBe(false); + }); - vm.$el.querySelector('.btn').click(); + it('resets detailJob when clicking header button', async () => { + await wrapper.find('.btn').trigger('click'); - expect(vm.setDetailJob).toHaveBeenCalledWith(null); + expect(store.dispatch).toHaveBeenCalledWith('pipelines/setDetailJob', null); }); it('renders raw path link', () => { - expect(vm.$el.querySelector('.controllers-buttons').getAttribute('href')).toBe( - `${TEST_HOST}/raw`, - ); + expect(wrapper.find('.controllers-buttons').attributes('href')).toBe(`${TEST_HOST}/raw`); }); }); describe('scroll buttons', () => { beforeEach(() => { - vm = createComponent(); - jest.spyOn(vm, 'fetchJobLogs').mockResolvedValue(); - }); - - afterEach(() => { - vm.$destroy(); + createComponent(); }); it.each` - fnName | btnName | scrollPos - ${'scrollDown'} | ${'down'} | ${0} - ${'scrollUp'} | ${'up'} | ${1} - `('triggers $fnName when clicking $btnName button', async ({ fnName, scrollPos }) => { - jest.spyOn(vm, fnName).mockImplementation(); - - vm = vm.$mount(); + fnName | btnName | scrollPos | targetScrollPos + ${'scroll down'} | ${'down'} | ${0} | ${200} + ${'scroll up'} | ${'up'} | ${200} | ${0} + `('triggers $fnName when clicking $btnName button', async ({ scrollPos, targetScrollPos }) => { + jest.spyOn(findBuildJobLog().element, 'offsetHeight', 'get').mockReturnValue(0); + jest.spyOn(findBuildJobLog().element, 'scrollHeight', 'get').mockReturnValue(200); + jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(scrollPos); + findBuildJobLog().element.scrollTo.mockReset(); - vm.scrollPos = scrollPos; - - await nextTick(); - vm.$el.querySelector('.btn-scroll:not([disabled])').click(); - expect(vm[fnName]).toHaveBeenCalled(); - }); - }); - - describe('scrollDown', () => { - beforeEach(() => { - vm = vm.$mount(); - - jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation(); - }); - - it('scrolls build trace to bottom', () => { - jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(1000); - - vm.scrollDown(); - - expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 1000); - }); - }); - - describe('scrollUp', () => { - beforeEach(() => { - vm = vm.$mount(); - - jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation(); - }); + await findBuildJobLog().trigger('scroll'); // trigger button updates - it('scrolls build trace to top', () => { - vm.scrollUp(); + await wrapper.find('.controllers button:not(:disabled)').trigger('click'); - expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 0); + expect(findBuildJobLog().element.scrollTo).toHaveBeenCalledWith(0, targetScrollPos); }); }); - describe('scrollBuildLog', () => { + describe('scrolling build log', () => { beforeEach(() => { - vm = vm.$mount(); - jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation(); - jest.spyOn(vm.$refs.buildJobLog, 'offsetHeight', 'get').mockReturnValue(100); - jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(200); + jest.spyOn(findBuildJobLog().element, 'offsetHeight', 'get').mockReturnValue(100); + jest.spyOn(findBuildJobLog().element, 'scrollHeight', 'get').mockReturnValue(200); }); - it('sets scrollPos to bottom when at the bottom', () => { - jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(100); + it('keeps scroll at bottom when already at the bottom', async () => { + jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(100); - vm.scrollBuildLog(); + await findBuildJobLog().trigger('scroll'); - expect(vm.scrollPos).toBe(1); + expect(findScrollToBottomButton().attributes('disabled')).toBe('disabled'); + expect(findScrollToTopButton().attributes('disabled')).not.toBe('disabled'); }); - it('sets scrollPos to top when at the top', () => { - jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(0); - vm.scrollPos = 1; + it('keeps scroll at top when already at top', async () => { + jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(0); - vm.scrollBuildLog(); + await findBuildJobLog().trigger('scroll'); - expect(vm.scrollPos).toBe(0); + expect(findScrollToBottomButton().attributes('disabled')).not.toBe('disabled'); + expect(findScrollToTopButton().attributes('disabled')).toBe('disabled'); }); - it('resets scrollPos when not at top or bottom', () => { - jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(10); + it('resets scroll when not at top or bottom', async () => { + jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(10); - vm.scrollBuildLog(); + await findBuildJobLog().trigger('scroll'); - expect(vm.scrollPos).toBe(''); + expect(findScrollToBottomButton().attributes('disabled')).not.toBe('disabled'); + expect(findScrollToTopButton().attributes('disabled')).not.toBe('disabled'); }); }); }); diff --git a/spec/frontend/ide/components/jobs/item_spec.js b/spec/frontend/ide/components/jobs/item_spec.js index c76760a5522..32e27333e42 100644 --- a/spec/frontend/ide/components/jobs/item_spec.js +++ b/spec/frontend/ide/components/jobs/item_spec.js @@ -1,36 +1,38 @@ -import Vue, { nextTick } from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; +import { mount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; + import JobItem from '~/ide/components/jobs/item.vue'; import { jobs } from '../../mock_data'; describe('IDE jobs item', () => { - const Component = Vue.extend(JobItem); const job = jobs[0]; - let vm; + let wrapper; beforeEach(() => { - vm = mountComponent(Component, { - job, - }); + wrapper = mount(JobItem, { propsData: { job } }); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders job details', () => { - expect(vm.$el.textContent).toContain(job.name); - expect(vm.$el.textContent).toContain(`#${job.id}`); + expect(wrapper.text()).toContain(job.name); + expect(wrapper.text()).toContain(`#${job.id}`); }); it('renders CI icon', () => { - expect(vm.$el.querySelector('[data-testid="status_success_borderless-icon"]')).not.toBe(null); + expect(wrapper.find('[data-testid="status_success_borderless-icon"]').exists()).toBe(true); }); it('does not render view logs button if not started', async () => { - vm.job.started = false; + await wrapper.setProps({ + job: { + ...jobs[0], + started: false, + }, + }); - await nextTick(); - expect(vm.$el.querySelector('.btn')).toBe(null); + expect(wrapper.findComponent(GlButton).exists()).toBe(false); }); }); diff --git a/spec/frontend/ide/components/jobs/stage_spec.js b/spec/frontend/ide/components/jobs/stage_spec.js index 1d5e5743a4d..52fbff2f497 100644 --- a/spec/frontend/ide/components/jobs/stage_spec.js +++ b/spec/frontend/ide/components/jobs/stage_spec.js @@ -18,8 +18,9 @@ describe('IDE pipeline stage', () => { }, }; - const findHeader = () => wrapper.findComponent({ ref: 'cardHeader' }); - const findJobList = () => wrapper.findComponent({ ref: 'jobList' }); + const findHeader = () => wrapper.find('[data-testid="card-header"]'); + const findJobList = () => wrapper.find('[data-testid="job-list"]'); + const findStageTitle = () => wrapper.find('[data-testid="stage-title"]'); const createComponent = (props) => { wrapper = shallowMount(Stage, { @@ -65,9 +66,9 @@ describe('IDE pipeline stage', () => { expect(wrapper.emitted().clickViewLog[0][0]).toBe(job); }); - it('renders stage details & icon', () => { + it('renders stage title', () => { createComponent(); - expect(wrapper.element).toMatchSnapshot(); + expect(findStageTitle().isVisible()).toBe(true); }); describe('when collapsed', () => { |