diff options
Diffstat (limited to 'spec/frontend/jobs')
-rw-r--r-- | spec/frontend/jobs/components/log/line_spec.js | 136 | ||||
-rw-r--r-- | spec/frontend/jobs/components/unmet_prerequisites_block_spec.js | 34 | ||||
-rw-r--r-- | spec/frontend/jobs/mixins/delayed_job_mixin_spec.js | 88 | ||||
-rw-r--r-- | spec/frontend/jobs/store/actions_spec.js | 66 | ||||
-rw-r--r-- | spec/frontend/jobs/store/mutations_spec.js | 1 |
5 files changed, 218 insertions, 107 deletions
diff --git a/spec/frontend/jobs/components/log/line_spec.js b/spec/frontend/jobs/components/log/line_spec.js index 314b23ec29b..914ae2424c8 100644 --- a/spec/frontend/jobs/components/log/line_spec.js +++ b/spec/frontend/jobs/components/log/line_spec.js @@ -4,6 +4,7 @@ import LineNumber from '~/jobs/components/log/line_number.vue'; 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: { @@ -21,7 +22,6 @@ const mockProps = ({ text = 'Running with gitlab-runner 12.1.0 (de7731dd)' } = { describe('Job Log Line', () => { let wrapper; let data; - let originalGon; const createComponent = (props = {}) => { wrapper = shallowMount(Line, { @@ -33,25 +33,17 @@ describe('Job Log Line', () => { const findLine = () => wrapper.find('span'); const findLink = () => findLine().find('a'); - const findLinksAt = i => - findLine() - .findAll('a') - .at(i); + const findLinks = () => findLine().findAll('a'); + const findLinkAttributeByIndex = i => + findLinks() + .at(i) + .attributes(); beforeEach(() => { - originalGon = window.gon; - window.gon.features = { - ciJobLineLinks: false, - }; - data = mockProps(); createComponent(data); }); - afterEach(() => { - window.gon = originalGon; - }); - it('renders the line number component', () => { expect(wrapper.find(LineNumber).exists()).toBe(true); }); @@ -64,44 +56,7 @@ describe('Job Log Line', () => { expect(findLine().classes()).toContain(data.line.content[0].style); }); - describe.each([true, false])('when feature ci_job_line_links enabled = %p', ciJobLineLinks => { - beforeEach(() => { - window.gon.features = { - ciJobLineLinks, - }; - }); - - it('renders text with symbols', () => { - const text = 'apt-get update < /dev/null > /dev/null'; - createComponent(mockProps({ text })); - - expect(findLine().text()).toBe(text); - }); - - it.each` - tag | text - ${'a'} | ${'<a href="#">linked</a>'} - ${'script'} | ${'<script>doEvil();</script>'} - ${'strong'} | ${'<strong>highlighted</strong>'} - `('escapes `<$tag>` tags in text', ({ tag, text }) => { - createComponent(mockProps({ text })); - - expect( - findLine() - .find(tag) - .exists(), - ).toBe(false); - expect(findLine().text()).toBe(text); - }); - }); - - describe('when ci_job_line_links is enabled', () => { - beforeEach(() => { - window.gon.features = { - ciJobLineLinks: true, - }; - }); - + describe('job urls as links', () => { it('renders an http link', () => { createComponent(mockProps({ text: httpUrl })); @@ -116,15 +71,6 @@ describe('Job Log Line', () => { expect(findLink().attributes().href).toBe(httpsUrl); }); - it('renders a multiple links surrounded by text', () => { - createComponent(mockProps({ text: `My HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl}` })); - expect(findLine().text()).toBe( - 'My HTTP url: http://example.com and my HTTPS url: https://example.com', - ); - expect(findLinksAt(0).attributes().href).toBe(httpUrl); - expect(findLinksAt(1).attributes().href).toBe(httpsUrl); - }); - it('renders a link with rel nofollow and noopener', () => { createComponent(mockProps({ text: httpsUrl })); @@ -137,26 +83,70 @@ describe('Job Log Line', () => { expect(findLink().classes()).toEqual(['gl-reset-color!', 'gl-text-decoration-underline']); }); - it('render links surrounded by text', () => { + 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 multiple links surrounded by text', () => { createComponent( - mockProps({ text: `My HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl} are here.` }), + mockProps({ text: `Well, my HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl}` }), ); expect(findLine().text()).toBe( - 'My HTTP url: http://example.com and my HTTPS url: https://example.com are here.', + 'Well, my HTTP url: http://example.com and my HTTPS url: https://example.com', ); - expect(findLinksAt(0).attributes().href).toBe(httpUrl); - expect(findLinksAt(1).attributes().href).toBe(httpsUrl); + + 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 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 - test.each` - type | text - ${'js'} | ${jshref} - ${'file'} | ${'file:///a-file'} - ${'ftp'} | ${'ftp://example.com/file'} - ${'email'} | ${'email@example.com'} - ${'no scheme'} | ${'example.com/page'} + 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); diff --git a/spec/frontend/jobs/components/unmet_prerequisites_block_spec.js b/spec/frontend/jobs/components/unmet_prerequisites_block_spec.js index 68fcb321214..9092d3f8163 100644 --- a/spec/frontend/jobs/components/unmet_prerequisites_block_spec.js +++ b/spec/frontend/jobs/components/unmet_prerequisites_block_spec.js @@ -1,37 +1,41 @@ -import Vue from 'vue'; -import component from '~/jobs/components/unmet_prerequisites_block.vue'; -import mountComponent from '../../helpers/vue_mount_component_helper'; +import { shallowMount } from '@vue/test-utils'; +import { GlAlert, GlLink } from '@gitlab/ui'; +import UnmetPrerequisitesBlock from '~/jobs/components/unmet_prerequisites_block.vue'; describe('Unmet Prerequisites Block Job component', () => { - const Component = Vue.extend(component); - let vm; + let wrapper; const helpPath = '/user/project/clusters/index.html#troubleshooting-failed-deployment-jobs'; - beforeEach(() => { - vm = mountComponent(Component, { - hasNoRunnersForProject: true, - helpPath, + const createComponent = () => { + wrapper = shallowMount(UnmetPrerequisitesBlock, { + propsData: { + helpPath, + }, }); + }; + + beforeEach(() => { + createComponent(); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('renders an alert with the correct message', () => { - const container = vm.$el.querySelector('.js-failed-unmet-prerequisites'); + const container = wrapper.find(GlAlert); const alertMessage = 'This job failed because the necessary resources were not successfully created.'; expect(container).not.toBeNull(); - expect(container.innerHTML).toContain(alertMessage); + expect(container.text()).toContain(alertMessage); }); it('renders link to help page', () => { - const helpLink = vm.$el.querySelector('.js-help-path'); + const helpLink = wrapper.find(GlLink); expect(helpLink).not.toBeNull(); - expect(helpLink.innerHTML).toContain('More information'); - expect(helpLink.getAttribute('href')).toEqual(helpPath); + expect(helpLink.text()).toContain('More information'); + expect(helpLink.attributes().href).toEqual(helpPath); }); }); diff --git a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js b/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js index 2f7a6030650..2175610b7a6 100644 --- a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js +++ b/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js @@ -44,34 +44,84 @@ describe('DelayedJobMixin', () => { }); }); - describe('if job is delayed job', () => { - let remainingTimeInMilliseconds = 42000; + describe('in REST component', () => { + describe('if job is delayed job', () => { + let remainingTimeInMilliseconds = 42000; - beforeEach(() => { - jest - .spyOn(Date, 'now') - .mockImplementation( - () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds, - ); + beforeEach(() => { + jest + .spyOn(Date, 'now') + .mockImplementation( + () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds, + ); - vm = mountComponent(dummyComponent, { - job: delayedJobFixture, + vm = mountComponent(dummyComponent, { + job: delayedJobFixture, + }); + }); + + describe('after mounting', () => { + beforeEach(() => vm.$nextTick()); + + it('sets remaining time', () => { + expect(vm.$el.innerText).toBe('00:00:42'); + }); + + it('updates remaining time', () => { + remainingTimeInMilliseconds = 41000; + jest.advanceTimersByTime(1000); + + return vm.$nextTick().then(() => { + expect(vm.$el.innerText).toBe('00:00:41'); + }); + }); }); }); + }); - describe('after mounting', () => { - beforeEach(() => vm.$nextTick()); + describe('in GraphQL component', () => { + const mockGraphQlJob = { + name: 'build_b', + scheduledAt: new Date(delayedJobFixture.scheduled_at), + status: { + icon: 'status_success', + tooltip: 'passed', + hasDetails: true, + detailsPath: '/root/abcd-dag/-/jobs/1515', + group: 'success', + action: null, + }, + }; + + describe('if job is delayed job', () => { + let remainingTimeInMilliseconds = 42000; - it('sets remaining time', () => { - expect(vm.$el.innerText).toBe('00:00:42'); + beforeEach(() => { + jest + .spyOn(Date, 'now') + .mockImplementation( + () => mockGraphQlJob.scheduledAt.getTime() - remainingTimeInMilliseconds, + ); + + vm = mountComponent(dummyComponent, { + job: mockGraphQlJob, + }); }); - it('updates remaining time', () => { - remainingTimeInMilliseconds = 41000; - jest.advanceTimersByTime(1000); + describe('after mounting', () => { + beforeEach(() => vm.$nextTick()); + + it('sets remaining time', () => { + expect(vm.$el.innerText).toBe('00:00:42'); + }); + + it('updates remaining time', () => { + remainingTimeInMilliseconds = 41000; + jest.advanceTimersByTime(1000); - return vm.$nextTick().then(() => { - expect(vm.$el.innerText).toBe('00:00:41'); + return vm.$nextTick().then(() => { + expect(vm.$el.innerText).toBe('00:00:41'); + }); }); }); }); diff --git a/spec/frontend/jobs/store/actions_spec.js b/spec/frontend/jobs/store/actions_spec.js index 91bd5521f70..26547d12ac7 100644 --- a/spec/frontend/jobs/store/actions_spec.js +++ b/spec/frontend/jobs/store/actions_spec.js @@ -27,6 +27,7 @@ import { hideSidebar, showSidebar, toggleSidebar, + triggerManualJob, } from '~/jobs/store/actions'; import state from '~/jobs/store/state'; import * as types from '~/jobs/store/mutation_types'; @@ -158,6 +159,32 @@ describe('Job State actions', () => { ); }); }); + + it('fetchTrace is called only if the job has started or has a trace', done => { + mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, { id: 121212, name: 'karma' }); + + mockedState.job.started = true; + + testAction( + fetchJob, + null, + mockedState, + [], + [ + { + type: 'requestJob', + }, + { + payload: { id: 121212, name: 'karma' }, + type: 'receiveJobSuccess', + }, + { + type: 'fetchTrace', + }, + ], + done, + ); + }); }); describe('receiveJobSuccess', () => { @@ -509,4 +536,43 @@ describe('Job State actions', () => { ); }); }); + + describe('triggerManualJob', () => { + let mock; + + beforeEach(() => { + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + it('should dispatch fetchTrace', done => { + const playManualJobEndpoint = `${TEST_HOST}/manual-job/jobs/1000/play`; + + mock.onPost(playManualJobEndpoint).reply(200); + + mockedState.job = { + status: { + action: { + path: playManualJobEndpoint, + }, + }, + }; + + testAction( + triggerManualJob, + [{ id: '1', key: 'test_var', secret_value: 'test_value' }], + mockedState, + [], + [ + { + type: 'fetchTrace', + }, + ], + done, + ); + }); + }); }); diff --git a/spec/frontend/jobs/store/mutations_spec.js b/spec/frontend/jobs/store/mutations_spec.js index 608abc8f7c4..a8146ba93eb 100644 --- a/spec/frontend/jobs/store/mutations_spec.js +++ b/spec/frontend/jobs/store/mutations_spec.js @@ -153,6 +153,7 @@ describe('Jobs Store Mutations', () => { mutations[types.SET_TRACE_TIMEOUT](stateCopy, id); expect(stateCopy.traceTimeout).toEqual(id); + expect(stateCopy.isTraceComplete).toBe(false); }); }); |