diff options
author | Simon Knox <psimyn@gmail.com> | 2019-08-06 15:07:18 +1000 |
---|---|---|
committer | Simon Knox <psimyn@gmail.com> | 2019-08-06 15:07:18 +1000 |
commit | fc77b9df8b6a49c86e9c1eb949f1b1162470d2ee (patch) | |
tree | 96aad0a31543fa520626dc1c5efabff1367a0bab /spec/javascripts/jobs/components/job_app_spec.js | |
parent | 9c71bf3e6df2dcb20ea19df21a127823bbe5e615 (diff) | |
parent | fa216b0e86433192ba4e39a05f42217fb4685173 (diff) | |
download | gitlab-ce-alerts-dropdown-to-modal-part-2-ce.tar.gz |
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into alerts-dropdown-to-modal-part-2-cealerts-dropdown-to-modal-part-2-ce
Diffstat (limited to 'spec/javascripts/jobs/components/job_app_spec.js')
-rw-r--r-- | spec/javascripts/jobs/components/job_app_spec.js | 684 |
1 files changed, 301 insertions, 383 deletions
diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js index f28d2c2a882..d3c1cf831bb 100644 --- a/spec/javascripts/jobs/components/job_app_spec.js +++ b/spec/javascripts/jobs/components/job_app_spec.js @@ -3,7 +3,9 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import jobApp from '~/jobs/components/job_app.vue'; import createStore from '~/jobs/store'; +import * as types from '~/jobs/store/mutation_types'; import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { waitForMutation } from 'spec/helpers/vue_test_utils_helper'; import { resetStore } from '../store/helpers'; import job from '../mock_data'; @@ -19,12 +21,24 @@ describe('Job App ', () => { runnerHelpUrl: 'help/runner', deploymentHelpUrl: 'help/deployment', runnerSettingsUrl: 'settings/ci-cd/runners', + variablesSettingsUrl: 'settings/ci-cd/variables', terminalPath: 'jobs/123/terminal', pagePath: `${gl.TEST_HOST}jobs/123`, + projectPath: 'user-name/project-name', logState: 'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D', }; + const waitForJobReceived = () => waitForMutation(store, types.RECEIVE_JOB_SUCCESS); + const setupAndMount = ({ jobData = {}, traceData = {} } = {}) => { + mock.onGet(props.endpoint).replyOnce(200, { ...job, ...jobData }); + mock.onGet(`${props.pagePath}/trace.json`).reply(200, traceData); + + vm = mountComponentWithStore(Component, { props, store }); + + return waitForJobReceived(); + }; + beforeEach(() => { mock = new MockAdapter(axios); store = createStore(); @@ -38,103 +52,81 @@ describe('Job App ', () => { describe('while loading', () => { beforeEach(() => { - mock.onGet(props.endpoint).reply(200, job, {}); - mock.onGet(`${props.pagePath}/trace.json`).reply(200, {}); - vm = mountComponentWithStore(Component, { props, store }); + setupAndMount(); }); - it('renders loading icon', done => { + it('renders loading icon', () => { expect(vm.$el.querySelector('.js-job-loading')).not.toBeNull(); expect(vm.$el.querySelector('.js-job-sidebar')).toBeNull(); expect(vm.$el.querySelector('.js-job-content')).toBeNull(); - - setTimeout(() => { - done(); - }, 0); }); }); describe('with successful request', () => { - beforeEach(() => { - mock.onGet(`${props.pagePath}/trace.json`).replyOnce(200, {}); - }); - describe('Header section', () => { describe('job callout message', () => { it('should not render the reason when reason is absent', done => { - mock.onGet(props.endpoint).replyOnce(200, job); - vm = mountComponentWithStore(Component, { props, store }); - - setTimeout(() => { - expect(vm.shouldRenderCalloutMessage).toBe(false); - - done(); - }, 0); + setupAndMount() + .then(() => { + expect(vm.shouldRenderCalloutMessage).toBe(false); + }) + .then(done) + .catch(done.fail); }); it('should render the reason when reason is present', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { - callout_message: 'There is an unknown failure, please try again', - }), - ); - - vm = mountComponentWithStore(Component, { props, store }); - setTimeout(() => { - expect(vm.shouldRenderCalloutMessage).toBe(true); - done(); - }, 0); + setupAndMount({ + jobData: { + callout_message: 'There is an unkown failure, please try again', + }, + }) + .then(() => { + expect(vm.shouldRenderCalloutMessage).toBe(true); + }) + .then(done) + .catch(done.fail); }); }); describe('triggered job', () => { - beforeEach(() => { + beforeEach(done => { const aYearAgo = new Date(); aYearAgo.setFullYear(aYearAgo.getFullYear() - 1); - mock - .onGet(props.endpoint) - .replyOnce(200, Object.assign({}, job, { started: aYearAgo.toISOString() })); - vm = mountComponentWithStore(Component, { props, store }); + setupAndMount({ jobData: { started: aYearAgo.toISOString() } }) + .then(done) + .catch(done.fail); }); - it('should render provided job information', done => { - setTimeout(() => { - expect( - vm.$el - .querySelector('.header-main-content') - .textContent.replace(/\s+/g, ' ') - .trim(), - ).toContain('passed Job #4757 triggered 1 year ago by Root'); - done(); - }, 0); + it('should render provided job information', () => { + expect( + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), + ).toContain('passed Job #4757 triggered 1 year ago by Root'); }); - it('should render new issue link', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( - job.new_issue_path, - ); - done(); - }, 0); + it('should render new issue link', () => { + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + job.new_issue_path, + ); }); }); describe('created job', () => { it('should render created key', done => { - mock.onGet(props.endpoint).replyOnce(200, job); - vm = mountComponentWithStore(Component, { props, store }); - - setTimeout(() => { - expect( - vm.$el - .querySelector('.header-main-content') - .textContent.replace(/\s+/g, ' ') - .trim(), - ).toContain('passed Job #4757 created 3 weeks ago by Root'); - done(); - }, 0); + setupAndMount() + .then(() => { + expect( + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), + ).toContain('passed Job #4757 created 3 weeks ago by Root'); + }) + .then(done) + .catch(done.fail); }); }); }); @@ -142,9 +134,8 @@ describe('Job App ', () => { describe('stuck block', () => { describe('without active runners availabl', () => { it('renders stuck block when there are no runners', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { status: { group: 'pending', icon: 'status_pending', @@ -158,23 +149,23 @@ describe('Job App ', () => { online: false, }, tags: [], - }), - ); - vm = mountComponentWithStore(Component, { props, store }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull(); - expect(vm.$el.querySelector('.js-job-stuck .js-stuck-no-active-runner')).not.toBeNull(); - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull(); + expect( + vm.$el.querySelector('.js-job-stuck .js-stuck-no-active-runner'), + ).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('when available runners can not run specified tag', () => { it('renders tags in stuck block when there are no runners', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { status: { group: 'pending', icon: 'status_pending', @@ -187,27 +178,21 @@ describe('Job App ', () => { available: false, online: false, }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); - expect(vm.$el.querySelector('.js-job-stuck .js-stuck-with-tags')).not.toBeNull(); - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); + expect(vm.$el.querySelector('.js-job-stuck .js-stuck-with-tags')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('when runners are offline and build has tags', () => { it('renders message about job being stuck because of no runners with the specified tags', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { status: { group: 'pending', icon: 'status_pending', @@ -220,48 +205,35 @@ describe('Job App ', () => { available: true, online: true, }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); - expect(vm.$el.querySelector('.js-job-stuck .js-stuck-with-tags')).not.toBeNull(); - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); + expect(vm.$el.querySelector('.js-job-stuck .js-stuck-with-tags')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); it('does not renders stuck block when there are no runners', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { runners: { available: true }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-stuck')).toBeNull(); - - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-stuck')).toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('unmet prerequisites block', () => { it('renders unmet prerequisites block when there is an unmet prerequisites failure', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { status: { group: 'failed', icon: 'status_failed', @@ -281,104 +253,81 @@ describe('Job App ', () => { available: true, }, tags: [], - }), - ); - vm = mountComponentWithStore(Component, { props, store }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-failed')).not.toBeNull(); - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-failed')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('environments block', () => { it('renders environment block when job has environment', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { deployment_status: { environment: { environment_path: '/path', name: 'foo', }, }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-environment')).not.toBeNull(); - - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-environment')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); it('does not render environment block when job has environment', done => { - mock.onGet(props.endpoint).replyOnce(200, job); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-environment')).toBeNull(); - done(); - }, 0); + setupAndMount() + .then(() => { + expect(vm.$el.querySelector('.js-job-environment')).toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('erased block', () => { it('renders erased block when `erased` is true', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { erased_by: { username: 'root', web_url: 'gitlab.com/root', }, erased_at: '2016-11-07T11:11:16.525Z', - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-erased-block')).not.toBeNull(); - - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-erased-block')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); it('does not render erased block when `erased` is false', done => { - mock.onGet(props.endpoint).replyOnce(200, Object.assign({}, job, { erased_at: null })); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-erased-block')).toBeNull(); - - done(); - }, 0); + setupAndMount({ + jobData: { + erased_at: null, + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-erased-block')).toBeNull(); + }) + .then(done) + .catch(done.fail); }); }); describe('empty states block', () => { it('renders empty state when job does not have trace and is not running', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { has_trace: false, status: { group: 'pending', @@ -398,25 +347,18 @@ describe('Job App ', () => { path: '/path', }, }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); - - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); + }) + .then(done) + .catch(done.fail); }); it('does not render empty state when job does not have trace but it is running', done => { - mock.onGet(props.endpoint).replyOnce( - 200, - Object.assign({}, job, { + setupAndMount({ + jobData: { has_trace: false, status: { group: 'running', @@ -425,34 +367,23 @@ describe('Job App ', () => { text: 'running', details_path: 'path', }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); - - done(); - }, 0); + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); + }) + .then(done) + .catch(done.fail); }); it('does not render empty state when job has trace but it is not running', done => { - mock.onGet(props.endpoint).replyOnce(200, Object.assign({}, job, { has_trace: true })); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); - - done(); - }, 0); + setupAndMount({ jobData: { has_trace: true } }) + .then(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); + }) + .then(done) + .catch(done.fail); + done(); }); it('displays remaining time for a delayed job', done => { @@ -460,120 +391,114 @@ describe('Job App ', () => { spyOn(Date, 'now').and.callFake( () => new Date(delayedJobFixture.scheduled_at).getTime() - oneHourInMilliseconds, ); - mock.onGet(props.endpoint).replyOnce(200, { ...delayedJobFixture }); + setupAndMount({ jobData: delayedJobFixture }) + .then(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); - vm = mountComponentWithStore(Component, { - props, - store, - }); - - store.subscribeAction(action => { - if (action.type !== 'receiveJobSuccess') { - return; - } + const title = vm.$el.querySelector('.js-job-empty-state-title'); - Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); - - const title = vm.$el.querySelector('.js-job-empty-state-title'); + expect(title).toContainText('01:00:00'); + }) + .then(done) + .catch(done.fail); + }); + }); - expect(title).toContainText('01:00:00'); - done(); - }) - .catch(done.fail); - }); + describe('sidebar', () => { + it('has no blank blocks', done => { + setupAndMount({ + jobData: { + duration: null, + finished_at: null, + erased_at: null, + queued: null, + runner: null, + coverage: null, + tags: [], + cancel_path: null, + }, + }) + .then(() => { + vm.$el.querySelectorAll('.blocks-container > *').forEach(block => { + expect(block.textContent.trim()).not.toBe(''); + }); + }) + .then(done) + .catch(done.fail); }); }); }); describe('archived job', () => { - beforeEach(() => { - mock.onGet(props.endpoint).reply(200, Object.assign({}, job, { archived: true }), {}); - vm = mountComponentWithStore(Component, { - props, - store, - }); + beforeEach(done => { + setupAndMount({ jobData: { archived: true } }) + .then(done) + .catch(done.fail); }); - it('renders warning about job being archived', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-archived-job ')).not.toBeNull(); - done(); - }, 0); + it('renders warning about job being archived', () => { + expect(vm.$el.querySelector('.js-archived-job ')).not.toBeNull(); }); }); describe('non-archived job', () => { - beforeEach(() => { - mock.onGet(props.endpoint).reply(200, job, {}); - vm = mountComponentWithStore(Component, { - props, - store, - }); + beforeEach(done => { + setupAndMount() + .then(done) + .catch(done.fail); }); - it('does not warning about job being archived', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-archived-job ')).toBeNull(); - done(); - }, 0); + it('does not warning about job being archived', () => { + expect(vm.$el.querySelector('.js-archived-job ')).toBeNull(); }); }); describe('trace output', () => { - beforeEach(() => { - mock.onGet(props.endpoint).reply(200, job, {}); - }); - describe('with append flag', () => { it('appends the log content to the existing one', done => { - mock.onGet(`${props.pagePath}/trace.json`).reply(200, { - html: '<span>More<span>', - status: 'running', - state: 'newstate', - append: true, - complete: true, - }); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - vm.$store.state.trace = 'Update'; - - setTimeout(() => { - expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).toContain('Update'); - - done(); - }, 0); + setupAndMount({ + traceData: { + html: '<span>More<span>', + status: 'running', + state: 'newstate', + append: true, + complete: true, + }, + }) + .then(() => { + vm.$store.state.trace = 'Update'; + + return vm.$nextTick(); + }) + .then(() => { + expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).toContain('Update'); + }) + .then(done) + .catch(done.fail); }); }); describe('without append flag', () => { it('replaces the trace', done => { - mock.onGet(`${props.pagePath}/trace.json`).reply(200, { - html: '<span>Different<span>', - status: 'running', - append: false, - complete: true, - }); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - vm.$store.state.trace = 'Update'; - - setTimeout(() => { - expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).not.toContain( - 'Update', - ); + setupAndMount({ + traceData: { + html: '<span>Different<span>', + status: 'running', + append: false, + complete: true, + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).not.toContain( + 'Update', + ); - expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).toContain('Different'); - done(); - }, 0); + expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).toContain( + 'Different', + ); + }) + .then(done) + .catch(done.fail); }); }); @@ -589,83 +514,76 @@ describe('Job App ', () => { complete: true, }); - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-truncated-info').textContent.trim()).toContain( - '50 bytes', - ); - done(); - }, 0); + setupAndMount({ + traceData: { + html: '<span>Update</span>', + status: 'success', + append: false, + size: 50, + total: 100, + complete: true, + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-truncated-info').textContent.trim()).toContain( + '50 bytes', + ); + }) + .then(done) + .catch(done.fail); }); }); describe('when size is equal than total', () => { it('does not show the truncated information', done => { - mock.onGet(`${props.pagePath}/trace.json`).reply(200, { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 100, - total: 100, - complete: true, - }); - - vm = mountComponentWithStore(Component, { - props, - store, - }); - - setTimeout(() => { - expect(vm.$el.querySelector('.js-truncated-info').textContent.trim()).not.toContain( - '50 bytes', - ); - done(); - }, 0); + setupAndMount({ + traceData: { + html: '<span>Update</span>', + status: 'success', + append: false, + size: 100, + total: 100, + complete: true, + }, + }) + .then(() => { + expect(vm.$el.querySelector('.js-truncated-info').textContent.trim()).not.toContain( + '50 bytes', + ); + }) + .then(done) + .catch(done.fail); }); }); }); describe('trace controls', () => { - beforeEach(() => { - mock.onGet(`${props.pagePath}/trace.json`).reply(200, { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 50, - total: 100, - complete: true, - }); - - vm = mountComponentWithStore(Component, { - props, - store, - }); + beforeEach(done => { + setupAndMount({ + traceData: { + html: '<span>Update</span>', + status: 'success', + append: false, + size: 50, + total: 100, + complete: true, + }, + }) + .then(done) + .catch(done.fail); }); - it('should render scroll buttons', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-scroll-top')).not.toBeNull(); - expect(vm.$el.querySelector('.js-scroll-bottom')).not.toBeNull(); - done(); - }, 0); + it('should render scroll buttons', () => { + expect(vm.$el.querySelector('.js-scroll-top')).not.toBeNull(); + expect(vm.$el.querySelector('.js-scroll-bottom')).not.toBeNull(); }); - it('should render link to raw ouput', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-raw-link-controller')).not.toBeNull(); - done(); - }, 0); + it('should render link to raw ouput', () => { + expect(vm.$el.querySelector('.js-raw-link-controller')).not.toBeNull(); }); - it('should render link to erase job', done => { - setTimeout(() => { - expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull(); - done(); - }, 0); + it('should render link to erase job', () => { + expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull(); }); }); }); |