diff options
Diffstat (limited to 'spec')
17 files changed, 898 insertions, 755 deletions
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 32cd7c6e70a..28f7e4634a5 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -343,4 +343,76 @@ describe Projects::BlobController do end end end + + describe 'DELETE destroy' do + let(:user) { create(:user) } + let(:project_root_path) { project_tree_path(project, 'master') } + + before do + project.add_maintainer(user) + + sign_in(user) + end + + context 'for a file in a subdirectory' do + let(:default_params) do + { + namespace_id: project.namespace, + project_id: project, + id: 'master/files/whitespace', + original_branch: 'master', + branch_name: 'master', + commit_message: 'Delete whitespace' + } + end + + let(:after_delete_path) { project_tree_path(project, 'master/files') } + + it 'redirects to the sub directory' do + delete :destroy, default_params + + expect(response).to redirect_to(after_delete_path) + end + end + + context 'if deleted file is the last one in a subdirectory' do + let(:default_params) do + { + namespace_id: project.namespace, + project_id: project, + id: 'master/bar/branch-test.txt', + original_branch: 'master', + branch_name: 'master', + commit_message: 'Delete whitespace' + } + end + + it 'redirects to the project root' do + delete :destroy, default_params + + expect(response).to redirect_to(project_root_path) + end + + context 'when deleting a file in a branch other than master' do + let(:default_params) do + { + namespace_id: project.namespace, + project_id: project, + id: 'binary-encoding/foo/bar/.gitkeep', + original_branch: 'binary-encoding', + branch_name: 'binary-encoding', + commit_message: 'Delete whitespace' + } + end + + let(:after_delete_path) { project_tree_path(project, 'binary-encoding') } + + it 'redirects to the project root of the branch' do + delete :destroy, default_params + + expect(response).to redirect_to(after_delete_path) + end + end + end + end end diff --git a/spec/features/projects/files/user_deletes_files_spec.rb b/spec/features/projects/files/user_deletes_files_spec.rb index dcb7b947c61..614b11fa5c8 100644 --- a/spec/features/projects/files/user_deletes_files_spec.rb +++ b/spec/features/projects/files/user_deletes_files_spec.rb @@ -31,7 +31,7 @@ describe 'Projects > Files > User deletes files', :js do fill_in(:commit_message, with: 'New commit message', visible: true) click_button('Delete file') - expect(current_path).to eq(project_tree_path(project, 'master')) + expect(current_path).to eq(project_tree_path(project, 'master/')) expect(page).not_to have_content('.gitignore') end end diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb index e639f0cf82e..6ce37297a7e 100644 --- a/spec/features/projects/jobs/permissions_spec.rb +++ b/spec/features/projects/jobs/permissions_spec.rb @@ -67,7 +67,7 @@ describe 'Project Jobs Permissions' do it_behaves_like 'recent job page details responds with status', 200 do it 'renders job details', :js do expect(page).to have_content "Job ##{job.id}" - expect(page).to have_css '#build-trace' + expect(page).to have_css '.js-build-trace' end end diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index fc7b78ac21f..908c616f2fc 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -20,7 +20,7 @@ describe 'User browses a job', :js do wait_for_requests expect(page).to have_content("Job ##{build.id}") - expect(page).to have_css('#build-trace') + expect(page).to have_css('.js-build-trace') # scroll to the top of the page first execute_script "window.scrollTo(0,0)" diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index a3a301504ff..7f5c3ff6ed8 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -294,7 +294,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end end - describe 'Raw trace' do + describe 'Raw trace', :js do before do job.run! @@ -302,7 +302,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end it do - expect(page).to have_css('.js-raw-link') + wait_for_all_requests + expect(page).to have_css('.js-raw-link-controller') end end @@ -636,7 +637,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end end - context 'Canceled job' do + context 'Canceled job', :js do context 'with log' do let(:job) { create(:ci_build, :canceled, :trace_artifact, pipeline: pipeline) } @@ -645,7 +646,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end it 'renders job log' do - expect(page).to have_selector('.js-build-output') + wait_for_all_requests + expect(page).to have_selector('.js-build-trace') end end @@ -658,7 +660,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do it 'renders empty state' do expect(page).to have_content(job.detailed_status(user).illustration[:title]) - expect(page).not_to have_selector('.js-build-output') + expect(page).not_to have_selector('.js-build-trace') expect(page).to have_content('This job has been canceled') end end @@ -673,7 +675,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do it 'renders empty state' do expect(page).to have_content(job.detailed_status(user).illustration[:title]) - expect(page).not_to have_selector('.js-build-output') + expect(page).not_to have_selector('.js-build-trace') expect(page).to have_content('This job has been skipped') end end @@ -722,8 +724,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).to have_css('.js-build-sidebar.right-sidebar-collapsed', visible: false) - expect(page).not_to have_css('.js-build-sidebar.right-sidebar-expanded', visible: false) + expect(page).to have_css('.js-job-sidebar.right-sidebar-collapsed', visible: false) + expect(page).not_to have_css('.js-job-sidebar.right-sidebar-expanded', visible: false) end end @@ -734,8 +736,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).to have_css('.js-build-sidebar.right-sidebar-expanded') - expect(page).not_to have_css('.js-build-sidebar.right-sidebar-collpased') + expect(page).to have_css('.js-job-sidebar.right-sidebar-expanded') + expect(page).not_to have_css('.js-job-sidebar.right-sidebar-collpased') end end end diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index d6b5dec9e47..bc973407b25 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -1,295 +1,265 @@ -import $ from 'jquery'; -import MockAdapter from 'axios-mock-adapter'; -import axios from '~/lib/utils/axios_utils'; -import { numberToHumanSize } from '~/lib/utils/number_utils'; -import '~/lib/utils/datetime_utility'; -import Job from '~/job'; -import '~/breakpoints'; -import waitForPromises from 'spec/helpers/wait_for_promises'; - -describe('Job', () => { - const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`; - let mock; - let response; - let job; - - preloadFixtures('builds/build-with-artifacts.html.raw'); - - beforeEach(() => { - loadFixtures('builds/build-with-artifacts.html.raw'); - - spyOnDependency(Job, 'visitUrl'); - - response = {}; - - mock = new MockAdapter(axios); - - mock.onGet(new RegExp(`${JOB_URL}/trace.json?(.*)`)).reply(() => [200, response]); - }); - - afterEach(() => { - mock.restore(); - - clearTimeout(job.timeout); - }); - - describe('class constructor', () => { - beforeEach(() => { - jasmine.clock().install(); - }); - - afterEach(() => { - jasmine.clock().uninstall(); - }); - - describe('setup', () => { - beforeEach(function (done) { - job = new Job(); - - waitForPromises() - .then(done) - .catch(done.fail); - }); - - it('copies build options', function () { - expect(job.pagePath).toBe(JOB_URL); - expect(job.buildStatus).toBe('success'); - expect(job.buildStage).toBe('test'); - expect(job.state).toBe(''); - }); - }); - - describe('running build', () => { - it('updates the build trace on an interval', function (done) { - response = { - html: '<span>Update<span>', - status: 'running', - state: 'newstate', - append: true, - complete: false, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect($('#build-trace .js-build-output').text()).toMatch(/Update/); - expect(job.state).toBe('newstate'); - - response = { - html: '<span>More</span>', - status: 'running', - state: 'finalstate', - append: true, - complete: true, - }; - }) - .then(() => jasmine.clock().tick(4001)) - .then(waitForPromises) - .then(() => { - expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/); - expect(job.state).toBe('finalstate'); - }) - .then(done) - .catch(done.fail); - }); - - it('replaces the entire build trace', (done) => { - response = { - html: '<span>Update<span>', - status: 'running', - append: false, - complete: false, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect($('#build-trace .js-build-output').text()).toMatch(/Update/); - - response = { - html: '<span>Different</span>', - status: 'running', - append: false, - }; - }) - .then(() => jasmine.clock().tick(4001)) - .then(waitForPromises) - .then(() => { - expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/); - expect($('#build-trace .js-build-output').text()).toMatch(/Different/); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('truncated information', () => { - describe('when size is less than total', () => { - it('shows information about truncated log', (done) => { - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 50, - total: 100, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden'); - }) - .then(done) - .catch(done.fail); - }); - - it('shows the size in KiB', (done) => { - const size = 50; - - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size, - total: 100, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect( - document.querySelector('.js-truncated-info-size').textContent.trim(), - ).toEqual(`${numberToHumanSize(size)}`); - }) - .then(done) - .catch(done.fail); - }); - - it('shows incremented size', (done) => { - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 50, - total: 100, - complete: false, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect( - document.querySelector('.js-truncated-info-size').textContent.trim(), - ).toEqual(`${numberToHumanSize(50)}`); - - response = { - html: '<span>Update</span>', - status: 'success', - append: true, - size: 10, - total: 100, - complete: true, - }; - }) - .then(() => jasmine.clock().tick(4001)) - .then(waitForPromises) - .then(() => { - expect( - document.querySelector('.js-truncated-info-size').textContent.trim(), - ).toEqual(`${numberToHumanSize(60)}`); - }) - .then(done) - .catch(done.fail); - }); - - it('renders the raw link', () => { - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 50, - total: 100, - }; - - job = new Job(); - - expect( - document.querySelector('.js-raw-link').textContent.trim(), - ).toContain('Complete Raw'); - }); - }); - - describe('when size is equal than total', () => { - it('does not show the trunctated information', (done) => { - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 100, - total: 100, - }; - - job = new Job(); - - waitForPromises() - .then(() => { - expect(document.querySelector('.js-truncated-info').classList).toContain('hidden'); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('output trace', () => { - beforeEach((done) => { - response = { - html: '<span>Update</span>', - status: 'success', - append: false, - size: 50, - total: 100, - }; - - job = new Job(); - - waitForPromises() - .then(done) - .catch(done.fail); - }); - - it('should render trace controls', () => { - const controllers = document.querySelector('.controllers'); - - expect(controllers.querySelector('.js-raw-link-controller')).not.toBeNull(); - expect(controllers.querySelector('.js-scroll-up')).not.toBeNull(); - expect(controllers.querySelector('.js-scroll-down')).not.toBeNull(); - }); - - it('should render received output', () => { - expect( - document.querySelector('.js-build-output').innerHTML, - ).toEqual('<span>Update</span>'); - }); - }); - }); - - describe('getBuildTrace', () => { - it('should request build trace with state parameter', (done) => { - spyOn(axios, 'get').and.callThrough(); - job = new Job(); - - setTimeout(() => { - expect(axios.get).toHaveBeenCalledWith( - `${JOB_URL}/trace.json`, { params: { state: '' } }, - ); - done(); - }, 0); - }); - }); -}); +// import $ from 'jquery'; +// import MockAdapter from 'axios-mock-adapter'; +// import axios from '~/lib/utils/axios_utils'; +// import { numberToHumanSize } from '~/lib/utils/number_utils'; +// import '~/lib/utils/datetime_utility'; +// import Job from '~/job'; +// import '~/breakpoints'; +// import waitForPromises from 'spec/helpers/wait_for_promises'; + +// describe('Job', () => { +// const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`; +// let mock; +// let response; +// let job; + +// preloadFixtures('builds/build-with-artifacts.html.raw'); + +// beforeEach(() => { +// loadFixtures('builds/build-with-artifacts.html.raw'); + +// spyOnDependency(Job, 'visitUrl'); + +// response = {}; + +// mock = new MockAdapter(axios); + +// mock.onGet(new RegExp(`${JOB_URL}/trace.json?(.*)`)).reply(() => [200, response]); +// }); + +// afterEach(() => { +// mock.restore(); + +// clearTimeout(job.timeout); +// }); + +// describe('class constructor', () => { +// beforeEach(() => { +// jasmine.clock().install(); +// }); + +// afterEach(() => { +// jasmine.clock().uninstall(); +// }); + +// describe('running build', () => { +// it('updates the build trace on an interval', function (done) { +// response = { +// html: '<span>Update<span>', +// status: 'running', +// state: 'newstate', +// append: true, +// complete: false, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect($('#build-trace .js-build-output').text()).toMatch(/Update/); +// expect(job.state).toBe('newstate'); + +// response = { +// html: '<span>More</span>', +// status: 'running', +// state: 'finalstate', +// append: true, +// complete: true, +// }; +// }) +// .then(() => jasmine.clock().tick(4001)) +// .then(waitForPromises) +// .then(() => { +// expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/); +// expect(job.state).toBe('finalstate'); +// }) +// .then(done) +// .catch(done.fail); +// }); + +// it('replaces the entire build trace', (done) => { +// response = { +// html: '<span>Update<span>', +// status: 'running', +// append: false, +// complete: false, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect($('#build-trace .js-build-output').text()).toMatch(/Update/); + +// response = { +// html: '<span>Different</span>', +// status: 'running', +// append: false, +// }; +// }) +// .then(() => jasmine.clock().tick(4001)) +// .then(waitForPromises) +// .then(() => { +// expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/); +// expect($('#build-trace .js-build-output').text()).toMatch(/Different/); +// }) +// .then(done) +// .catch(done.fail); +// }); +// }); + +// describe('truncated information', () => { +// describe('when size is less than total', () => { +// it('shows information about truncated log', (done) => { +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size: 50, +// total: 100, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden'); +// }) +// .then(done) +// .catch(done.fail); +// }); + +// it('shows the size in KiB', (done) => { +// const size = 50; + +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size, +// total: 100, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect( +// document.querySelector('.js-truncated-info-size').textContent.trim(), +// ).toEqual(`${numberToHumanSize(size)}`); +// }) +// .then(done) +// .catch(done.fail); +// }); + +// it('shows incremented size', (done) => { +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size: 50, +// total: 100, +// complete: false, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect( +// document.querySelector('.js-truncated-info-size').textContent.trim(), +// ).toEqual(`${numberToHumanSize(50)}`); + +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: true, +// size: 10, +// total: 100, +// complete: true, +// }; +// }) +// .then(() => jasmine.clock().tick(4001)) +// .then(waitForPromises) +// .then(() => { +// expect( +// document.querySelector('.js-truncated-info-size').textContent.trim(), +// ).toEqual(`${numberToHumanSize(60)}`); +// }) +// .then(done) +// .catch(done.fail); +// }); + +// it('renders the raw link', () => { +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size: 50, +// total: 100, +// }; + +// job = new Job(); + +// expect( +// document.querySelector('.js-raw-link').textContent.trim(), +// ).toContain('Complete Raw'); +// }); +// }); + +// describe('when size is equal than total', () => { +// it('does not show the trunctated information', (done) => { +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size: 100, +// total: 100, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(() => { +// expect(document.querySelector('.js-truncated-info').classList).toContain('hidden'); +// }) +// .then(done) +// .catch(done.fail); +// }); +// }); +// }); + +// describe('output trace', () => { +// beforeEach((done) => { +// response = { +// html: '<span>Update</span>', +// status: 'success', +// append: false, +// size: 50, +// total: 100, +// }; + +// job = new Job(); + +// waitForPromises() +// .then(done) +// .catch(done.fail); +// }); + +// it('should render trace controls', () => { +// const controllers = document.querySelector('.controllers'); + +// expect(controllers.querySelector('.js-raw-link-controller')).not.toBeNull(); +// expect(controllers.querySelector('.js-scroll-up')).not.toBeNull(); +// expect(controllers.querySelector('.js-scroll-down')).not.toBeNull(); +// }); + +// it('should render received output', () => { +// expect( +// document.querySelector('.js-build-output').innerHTML, +// ).toEqual('<span>Update</span>'); +// }); +// }); +// }); + +// }); diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js index 6e0bcf801cd..e6d403dc826 100644 --- a/spec/javascripts/jobs/components/job_app_spec.js +++ b/spec/javascripts/jobs/components/job_app_spec.js @@ -1,75 +1,196 @@ import Vue from 'vue'; +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 { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { resetStore } from '../store/helpers'; +import job from '../mock_data'; describe('Job App ', () => { const Component = Vue.extend(jobApp); let store; let vm; - - const threeWeeksAgo = new Date(); - threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); - - const twoDaysAgo = new Date(); - twoDaysAgo.setDate(twoDaysAgo.getDate() - 2); - - const job = { - status: { - group: 'failed', - icon: 'status_failed', - label: 'failed', - text: 'failed', - details_path: 'path', - }, - id: 123, - created_at: threeWeeksAgo.toISOString(), - user: { - web_url: 'path', - name: 'Foo', - username: 'foobar', - email: 'foo@bar.com', - avatar_url: 'link', - }, - started: twoDaysAgo.toISOString(), - new_issue_path: 'path', - runners: { - available: false, - }, - tags: ['docker'], - has_trace: true, - }; + let mock; const props = { + endpoint: `${gl.TEST_HOST}jobs/123.json`, + runnerHelpUrl: 'help/runner', runnerSettingsUrl: 'settings/ci-cd/runners', + terminalPath: 'jobs/123/terminal', + pagePath: `${gl.TEST_HOST}jobs/123`, + logState: + 'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D', }; beforeEach(() => { + mock = new MockAdapter(axios); store = createStore(); }); afterEach(() => { + resetStore(store); vm.$destroy(); + mock.restore(); }); - describe('Header section', () => { - describe('job callout message', () => { - it('should not render the reason when reason is absent', () => { - store.dispatch('receiveJobSuccess', job); + describe('while loading', () => { + beforeEach(() => { + mock.onGet(props.endpoint).reply(200, job, {}); + mock.onGet(`${props.pagePath}/trace.json`).reply(200, {}); + vm = mountComponentWithStore(Component, { props, store }); + }); + + it('renders loading icon', done => { + 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 successfull 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); + }); + + 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); + }); + }); + + describe('triggered job', () => { + beforeEach(() => { + mock.onGet(props.endpoint).replyOnce(200, Object.assign({}, job, { started: '2017-05-24T10:59:52.000+01:00' })); + vm = mountComponentWithStore(Component, { props, store }); + }); + + it('should render provided job information', done => { + setTimeout(() => { + expect( + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), + ).toEqual('passed Job #4757 triggered 1 year ago by Root'); + done(); + }, 0); + }); + + it('should render new issue link', done => { + setTimeout(() => { + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + job.new_issue_path, + ); + done(); + }, 0); + }); + }); + + 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(), + ).toEqual('passed Job #4757 created 3 weeks ago by Root'); + done(); + }, 0); + }); + }); + }); + + describe('stuck block', () => { + it('renders stuck block when there are no runners', done => { + mock.onGet(props.endpoint).replyOnce( + 200, + Object.assign({}, job, { + status: { + group: 'pending', + icon: 'status_pending', + label: 'pending', + text: 'pending', + details_path: 'path', + }, + runners: { + available: false, + }, + }), + ); + vm = mountComponentWithStore(Component, { props, store }); + + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull(); + + done(); + }, 0); + }); + + it('renders tags in stuck block when there are no runners', done => { + mock.onGet(props.endpoint).replyOnce( + 200, + Object.assign({}, job, { + status: { + group: 'pending', + icon: 'status_pending', + label: 'pending', + text: 'pending', + details_path: 'path', + }, + runners: { + available: false, + }, + }), + ); vm = mountComponentWithStore(Component, { props, store, }); - expect(vm.shouldRenderCalloutMessage).toBe(false); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); + done(); + }, 0); }); - it('should render the reason when reason is present', () => { - store.dispatch( - 'receiveJobSuccess', + it('does not renders stuck block when there are no runners', done => { + mock.onGet(props.endpoint).replyOnce( + 200, Object.assign({}, job, { - callout_message: 'There is an unknown failure, please try again', + runners: { available: true }, }), ); @@ -78,246 +199,324 @@ describe('Job App ', () => { store, }); - expect(vm.shouldRenderCalloutMessage).toBe(true); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-stuck')).toBeNull(); + + done(); + }, 0); }); }); - describe('triggered job', () => { - beforeEach(() => { - store.dispatch('receiveJobSuccess', job); + describe('environments block', () => { + it('renders environment block when job has environment', done => { + mock.onGet(props.endpoint).replyOnce( + 200, + Object.assign({}, job, { + deployment_status: { + environment: { + environment_path: '/path', + name: 'foo', + }, + }, + }), + ); vm = mountComponentWithStore(Component, { props, store, }); - }); - it('should render provided job information', () => { - expect( - vm.$el - .querySelector('.header-main-content') - .textContent.replace(/\s+/g, ' ') - .trim(), - ).toEqual('failed Job #123 triggered 2 days ago by Foo'); - }); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-environment')).not.toBeNull(); - it('should render new issue link', () => { - expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( - job.new_issue_path, - ); + done(); + }, 0); }); - }); - describe('created job', () => { - it('should render created key', () => { - store.dispatch('receiveJobSuccess', Object.assign({}, job, { started: false })); + it('does not render environment block when job has environment', done => { + mock.onGet(props.endpoint).replyOnce(200, job); vm = mountComponentWithStore(Component, { props, store, }); - expect( - vm.$el - .querySelector('.header-main-content') - .textContent.replace(/\s+/g, ' ') - .trim(), - ).toEqual('failed Job #123 created 3 weeks ago by Foo'); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-environment')).toBeNull(); + done(); + }, 0); }); }); - }); - describe('stuck block', () => { - it('renders stuck block when there are no runners', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - status: { - group: 'pending', - icon: 'status_pending', - label: 'pending', - text: 'pending', - details_path: 'path', - }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, - }); + describe('erased block', () => { + it('renders erased block when `erased` is true', done => { + mock.onGet(props.endpoint).replyOnce( + 200, + Object.assign({}, job, { + erased_by: { + username: 'root', + web_url: 'gitlab.com/root', + }, + erased_at: '2016-11-07T11:11:16.525Z', + }), + ); - expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull(); - }); + vm = mountComponentWithStore(Component, { + props, + store, + }); - it('renders tags in stuck block when there are no runners', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - status: { - group: 'pending', - icon: 'status_pending', - label: 'pending', - text: 'pending', - details_path: 'path', - }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-erased-block')).not.toBeNull(); + + done(); + }, 0); }); - expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]); - }); + it('does not render erased block when `erased` is false', done => { + mock.onGet(props.endpoint).replyOnce(200, Object.assign({}, job, { erased_at: null })); - it(' does not renders stuck block when there are no runners', () => { - store.dispatch('receiveJobSuccess', Object.assign({}, job, { runners: { available: true } })); + vm = mountComponentWithStore(Component, { + props, + store, + }); - vm = mountComponentWithStore(Component, { - props, - store, - }); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-erased-block')).toBeNull(); - expect(vm.$el.querySelector('.js-job-stuck')).toBeNull(); + done(); + }, 0); + }); }); - }); - describe('environments block', () => { - it('renders environment block when job has environment', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - deployment_status: { - environment: { - environment_path: '/path', - name: 'foo', + 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, { + has_trace: false, + status: { + group: 'pending', + icon: 'status_pending', + label: 'pending', + text: 'pending', + details_path: 'path', + illustration: { + image: 'path', + size: '340', + title: 'Empty State', + content: 'This is an empty state', + }, + action: { + button_title: 'Retry job', + method: 'post', + path: '/path', + }, }, - }, - }), - ); + }), + ); - vm = mountComponentWithStore(Component, { - props, - store, + vm = mountComponentWithStore(Component, { + props, + store, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); + + done(); + }, 0); }); - expect(vm.$el.querySelector('.js-job-environment')).not.toBeNull(); - }); + 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, { + has_trace: false, + status: { + group: 'running', + icon: 'status_running', + label: 'running', + text: 'running', + details_path: 'path', + }, + }), + ); + + vm = mountComponentWithStore(Component, { + props, + store, + }); - it('does not render environment block when job has environment', () => { - store.dispatch('receiveJobSuccess', job); + setTimeout(() => { + expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); - vm = mountComponentWithStore(Component, { - props, - store, + done(); + }, 0); }); - expect(vm.$el.querySelector('.js-job-environment')).toBeNull(); - }); - }); + 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, + }); - describe('erased block', () => { - it('renders erased block when `erased` is true', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - 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-empty-state')).toBeNull(); + + done(); + }, 0); }); + }); + }); - expect(vm.$el.querySelector('.js-job-erased-block')).not.toBeNull(); + describe('trace output', () => { + beforeEach(() => { + mock.onGet(props.endpoint).reply(200, job, {}); }); - it('does not render erased block when `erased` is false', () => { - store.dispatch('receiveJobSuccess', Object.assign({}, job, { erased_at: null })); + 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 = mountComponentWithStore(Component, { + props, + store, + }); - expect(vm.$el.querySelector('.js-job-erased-block')).toBeNull(); - }); - }); + vm.$store.state.trace = 'Update'; - describe('empty states block', () => { - it('renders empty state when job does not have trace and is not running', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - has_trace: false, - status: { - group: 'pending', - icon: 'status_pending', - label: 'pending', - text: 'pending', - details_path: 'path', - illustration: { - image: 'path', - size: '340', - title: 'Empty State', - content: 'This is an empty state', - }, - action: { - button_title: 'Retry job', - method: 'post', - path: '/path', - }, - }, - }), - ); + setTimeout(() => { + expect(vm.$el.querySelector('.js-build-trace').textContent.trim()).toContain('Update'); - vm = mountComponentWithStore(Component, { - props, - store, + done(); + }, 0); }); + }); + + 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, + }); - expect(vm.$el.querySelector('.js-job-empty-state')).not.toBeNull(); + vm = mountComponentWithStore(Component, { + props, + store, + }); + vm.$store.state.trace = 'Update'; + + setTimeout(() => { + 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); + }); }); - it('does not render empty state when job does not have trace but it is running', () => { - store.dispatch( - 'receiveJobSuccess', - Object.assign({}, job, { - has_trace: false, - status: { - group: 'running', - icon: 'status_running', - label: 'running', - text: 'running', - details_path: 'path', - }, - }), - ); - - vm = mountComponentWithStore(Component, { - props, - store, + describe('truncated information', () => { + describe('when size is less than total', () => { + it('shows information about truncated log', done => { + 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, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.js-truncated-info').textContent.trim()).toContain( + '50 bytes', + ); + done(); + }, 0); + }); }); - expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); + 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); + }); + }); }); - it('does not render empty state when job has trace but it is not running', () => { - store.dispatch('receiveJobSuccess', Object.assign({}, job, { has_trace: true })); + 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, + }); + }); + + 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); + }); - vm = mountComponentWithStore(Component, { - props, - store, + it('should render link to raw ouput', done => { + setTimeout(() => { + expect(vm.$el.querySelector('.js-raw-link-controller')).not.toBeNull(); + done(); + }, 0); }); - expect(vm.$el.querySelector('.js-job-empty-state')).toBeNull(); + it('should render link to erase job', done => { + setTimeout(() => { + expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull(); + done(); + }, 0); + }); }); }); }); diff --git a/spec/javascripts/jobs/components/job_log_spec.js b/spec/javascripts/jobs/components/job_log_spec.js index 1011512360d..413a96e502a 100644 --- a/spec/javascripts/jobs/components/job_log_spec.js +++ b/spec/javascripts/jobs/components/job_log_spec.js @@ -1,21 +1,32 @@ import Vue from 'vue'; import component from '~/jobs/components/job_log.vue'; -import mountComponent from '../../helpers/vue_mount_component_helper'; +import createStore from '~/jobs/store'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { resetStore } from '../store/helpers'; describe('Job Log', () => { const Component = Vue.extend(component); + let store; let vm; const trace = 'Running with gitlab-runner 11.1.0 (081978aa)<br> on docker-auto-scale-com d5ae8d25<br>Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29 ...<br>'; + beforeEach(() => { + store = createStore(); + }); + afterEach(() => { + resetStore(store); vm.$destroy(); }); it('renders provided trace', () => { - vm = mountComponent(Component, { - trace, - isComplete: true, + vm = mountComponentWithStore(Component, { + props: { + trace, + isComplete: true, + }, + store, }); expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)'); @@ -23,9 +34,12 @@ describe('Job Log', () => { describe('while receiving trace', () => { it('renders animation', () => { - vm = mountComponent(Component, { - trace, - isComplete: true, + vm = mountComponentWithStore(Component, { + props: { + trace, + isComplete: false, + }, + store, }); expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull(); @@ -34,9 +48,12 @@ describe('Job Log', () => { describe('when build trace has finishes', () => { it('does not render animation', () => { - vm = mountComponent(Component, { - trace, - isComplete: false, + vm = mountComponentWithStore(Component, { + props: { + trace, + isComplete: true, + }, + store, }); expect(vm.$el.querySelector('.js-log-animation')).toBeNull(); diff --git a/spec/javascripts/jobs/components/sidebar_spec.js b/spec/javascripts/jobs/components/sidebar_spec.js index ca4f62bd6ef..460a2e1b5da 100644 --- a/spec/javascripts/jobs/components/sidebar_spec.js +++ b/spec/javascripts/jobs/components/sidebar_spec.js @@ -18,15 +18,6 @@ describe('Sidebar details block', () => { vm.$destroy(); }); - describe('when it is loading', () => { - it('should render a loading spinner', () => { - store.dispatch('requestJob'); - vm = mountComponentWithStore(SidebarComponent, { store }); - - expect(vm.$el.querySelector('.fa-spinner')).toBeDefined(); - }); - }); - describe('when there is no retry path retry', () => { it('should not render a retry button', () => { const copy = Object.assign({}, job); @@ -52,12 +43,12 @@ describe('Sidebar details block', () => { describe('with terminal path', () => { it('renders terminal link', () => { - store.dispatch('receiveJobSuccess', job); + store.dispatch( + 'receiveJobSuccess', + Object.assign({}, job, { terminal_path: 'job/43123/terminal' }), + ); vm = mountComponentWithStore(SidebarComponent, { store, - props: { - terminalPath: 'job/43123/terminal', - }, }); expect(vm.$el.querySelector('.js-terminal-link')).not.toBeNull(); diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js index 4269b42e8b6..ca6fbabeeb6 100644 --- a/spec/javascripts/jobs/mock_data.js +++ b/spec/javascripts/jobs/mock_data.js @@ -31,6 +31,7 @@ export default { }, coverage: 20, erased_at: threeWeeksAgo.toISOString(), + erased: false, duration: 6.785563, tags: ['tag'], user: { @@ -131,6 +132,7 @@ export default { path: '/root/ci-mock/merge_requests/2', }, raw_path: '/root/ci-mock/builds/4757/raw', + has_trace: true, }; export const stages = [ diff --git a/spec/javascripts/jobs/store/actions_spec.js b/spec/javascripts/jobs/store/actions_spec.js index bc410ae614c..76af08b367d 100644 --- a/spec/javascripts/jobs/store/actions_spec.js +++ b/spec/javascripts/jobs/store/actions_spec.js @@ -2,9 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { setJobEndpoint, - setTraceEndpoint, - setStagesEndpoint, - setJobsEndpoint, + setTraceOptions, clearEtagPoll, stopPolling, requestJob, @@ -18,10 +16,6 @@ import { stopPollingTrace, receiveTraceSuccess, receiveTraceError, - fetchFavicon, - requestStatusFavicon, - receiveStatusFaviconSuccess, - requestStatusFaviconError, requestStages, fetchStages, receiveStagesSuccess, @@ -30,6 +24,9 @@ import { fetchJobsForStage, receiveJobsForStageSuccess, receiveJobsForStageError, + hideSidebar, + showSidebar, + toggleSidebar, } from '~/jobs/store/actions'; import state from '~/jobs/store/state'; import * as types from '~/jobs/store/mutation_types'; @@ -56,45 +53,75 @@ describe('Job State actions', () => { }); }); - describe('setTraceEndpoint', () => { - it('should commit SET_TRACE_ENDPOINT mutation', done => { + describe('setTraceOptions', () => { + it('should commit SET_TRACE_OPTIONS mutation', done => { testAction( - setTraceEndpoint, - 'job/872324/trace.json', + setTraceOptions, + { pagePath: 'job/872324/trace.json' }, mockedState, - [{ type: types.SET_TRACE_ENDPOINT, payload: 'job/872324/trace.json' }], + [{ type: types.SET_TRACE_OPTIONS, payload: { pagePath: 'job/872324/trace.json' } }], [], done, ); }); }); - describe('setStagesEndpoint', () => { - it('should commit SET_STAGES_ENDPOINT mutation', done => { + describe('hideSidebar', () => { + it('should commit HIDE_SIDEBAR mutation', done => { testAction( - setStagesEndpoint, - 'job/872324/stages.json', + hideSidebar, + null, mockedState, - [{ type: types.SET_STAGES_ENDPOINT, payload: 'job/872324/stages.json' }], + [{ type: types.HIDE_SIDEBAR }], [], done, ); }); }); - describe('setJobsEndpoint', () => { - it('should commit SET_JOBS_ENDPOINT mutation', done => { + describe('showSidebar', () => { + it('should commit HIDE_SIDEBAR mutation', done => { testAction( - setJobsEndpoint, - 'job/872324/stages/build.json', + showSidebar, + null, mockedState, - [{ type: types.SET_JOBS_ENDPOINT, payload: 'job/872324/stages/build.json' }], + [{ type: types.SHOW_SIDEBAR }], [], done, ); }); }); + describe('toggleSidebar', () => { + describe('when isSidebarOpen is true', () => { + it('should dispatch hideSidebar', done => { + testAction( + toggleSidebar, + null, + mockedState, + [], + [{ type: 'hideSidebar' }], + done, + ); + }); + }); + + describe('when isSidebarOpen is false', () => { + it('should dispatch showSidebar', done => { + mockedState.isSidebarOpen = false; + + testAction( + toggleSidebar, + null, + mockedState, + [], + [{ type: 'showSidebar' }], + done, + ); + }); + }); + }); + describe('requestJob', () => { it('should commit REQUEST_JOB mutation', done => { testAction(requestJob, null, mockedState, [{ type: types.REQUEST_JOB }], [], done); @@ -183,14 +210,14 @@ describe('Job State actions', () => { }); describe('scrollTop', () => { - it('should commit SCROLL_TO_TOP mutation', done => { - testAction(scrollTop, null, mockedState, [{ type: types.SCROLL_TO_TOP }], [], done); + it('should dispatch toggleScrollButtons action', done => { + testAction(scrollTop, null, mockedState, [], [{ type: 'toggleScrollButtons' }], done); }); }); describe('scrollBottom', () => { - it('should commit SCROLL_TO_BOTTOM mutation', done => { - testAction(scrollBottom, null, mockedState, [{ type: types.SCROLL_TO_BOTTOM }], [], done); + it('should dispatch toggleScrollButtons action', done => { + testAction(scrollBottom, null, mockedState, [], [{ type: 'toggleScrollButtons' }], done); }); }); @@ -215,7 +242,7 @@ describe('Job State actions', () => { }); describe('success', () => { - it('dispatches requestTrace, fetchFavicon, receiveTraceSuccess and stopPollingTrace when job is complete', done => { + it('dispatches requestTrace, receiveTraceSuccess and stopPollingTrace when job is complete', done => { mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(200, { html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :', complete: true, @@ -228,10 +255,8 @@ describe('Job State actions', () => { [], [ { - type: 'requestTrace', - }, - { - type: 'fetchFavicon', + type: 'toggleScrollisInBottom', + payload: true, }, { payload: { @@ -262,9 +287,6 @@ describe('Job State actions', () => { [], [ { - type: 'requestTrace', - }, - { type: 'receiveTraceError', }, ], @@ -313,104 +335,6 @@ describe('Job State actions', () => { }); }); - describe('fetchFavicon', () => { - let mock; - - beforeEach(() => { - mockedState.pagePath = `${TEST_HOST}/endpoint`; - mock = new MockAdapter(axios); - }); - - afterEach(() => { - mock.restore(); - }); - - describe('success', () => { - it('dispatches requestStatusFavicon and receiveStatusFaviconSuccess ', done => { - mock.onGet(`${TEST_HOST}/endpoint/status.json`).replyOnce(200); - - testAction( - fetchFavicon, - null, - mockedState, - [], - [ - { - type: 'requestStatusFavicon', - }, - { - type: 'receiveStatusFaviconSuccess', - }, - ], - done, - ); - }); - }); - - describe('error', () => { - beforeEach(() => { - mock.onGet(`${TEST_HOST}/endpoint/status.json`).replyOnce(500); - }); - - it('dispatches requestStatusFavicon and requestStatusFaviconError ', done => { - testAction( - fetchFavicon, - null, - mockedState, - [], - [ - { - type: 'requestStatusFavicon', - }, - { - type: 'requestStatusFaviconError', - }, - ], - done, - ); - }); - }); - }); - - describe('requestStatusFavicon', () => { - it('should commit REQUEST_STATUS_FAVICON mutation ', done => { - testAction( - requestStatusFavicon, - null, - mockedState, - [{ type: types.REQUEST_STATUS_FAVICON }], - [], - done, - ); - }); - }); - - describe('receiveStatusFaviconSuccess', () => { - it('should commit RECEIVE_STATUS_FAVICON_SUCCESS mutation ', done => { - testAction( - receiveStatusFaviconSuccess, - null, - mockedState, - [{ type: types.RECEIVE_STATUS_FAVICON_SUCCESS }], - [], - done, - ); - }); - }); - - describe('requestStatusFaviconError', () => { - it('should commit RECEIVE_STATUS_FAVICON_ERROR mutation ', done => { - testAction( - requestStatusFaviconError, - null, - mockedState, - [{ type: types.RECEIVE_STATUS_FAVICON_ERROR }], - [], - done, - ); - }); - }); - describe('requestStages', () => { it('should commit REQUEST_STAGES mutation ', done => { testAction(requestStages, null, mockedState, [{ type: types.REQUEST_STAGES }], [], done); diff --git a/spec/javascripts/jobs/store/helpers.js b/spec/javascripts/jobs/store/helpers.js new file mode 100644 index 00000000000..81a769b4a6e --- /dev/null +++ b/spec/javascripts/jobs/store/helpers.js @@ -0,0 +1,6 @@ +import state from '~/jobs/store/state'; + +// eslint-disable-next-line import/prefer-default-export +export const resetStore = store => { + store.replaceState(state()); +}; diff --git a/spec/javascripts/jobs/store/mutations_spec.js b/spec/javascripts/jobs/store/mutations_spec.js index c058a3b3d51..9bbf4ba8951 100644 --- a/spec/javascripts/jobs/store/mutations_spec.js +++ b/spec/javascripts/jobs/store/mutations_spec.js @@ -20,27 +20,19 @@ describe('Jobs Store Mutations', () => { }); }); - describe('REQUEST_STATUS_FAVICON', () => { - it('should set fetchingStatusFavicon to true', () => { - mutations[types.REQUEST_STATUS_FAVICON](stateCopy); + describe('HIDE_SIDEBAR', () => { + it('should set isSidebarOpen to false', () => { + mutations[types.HIDE_SIDEBAR](stateCopy); - expect(stateCopy.fetchingStatusFavicon).toEqual(true); + expect(stateCopy.isSidebarOpen).toEqual(false); }); }); - describe('RECEIVE_STATUS_FAVICON_SUCCESS', () => { - it('should set fetchingStatusFavicon to false', () => { - mutations[types.RECEIVE_STATUS_FAVICON_SUCCESS](stateCopy); + describe('SHOW_SIDEBAR', () => { + it('should set isSidebarOpen to true', () => { + mutations[types.SHOW_SIDEBAR](stateCopy); - expect(stateCopy.fetchingStatusFavicon).toEqual(false); - }); - }); - - describe('RECEIVE_STATUS_FAVICON_ERROR', () => { - it('should set fetchingStatusFavicon to false', () => { - mutations[types.RECEIVE_STATUS_FAVICON_ERROR](stateCopy); - - expect(stateCopy.fetchingStatusFavicon).toEqual(false); + expect(stateCopy.isSidebarOpen).toEqual(true); }); }); @@ -101,9 +93,7 @@ describe('Jobs Store Mutations', () => { it('resets trace state and sets error to true', () => { mutations[types.RECEIVE_TRACE_ERROR](stateCopy); - expect(stateCopy.isLoadingTrace).toEqual(false); expect(stateCopy.isTraceComplete).toEqual(true); - expect(stateCopy.hasTraceError).toEqual(true); }); }); @@ -156,39 +146,10 @@ describe('Jobs Store Mutations', () => { mutations[types.RECEIVE_JOB_ERROR](stateCopy); expect(stateCopy.isLoading).toEqual(false); - expect(stateCopy.hasError).toEqual(true); expect(stateCopy.job).toEqual({}); }); }); - describe('SCROLL_TO_TOP', () => { - beforeEach(() => { - mutations[types.SCROLL_TO_TOP](stateCopy); - }); - - it('sets isTraceScrolledToBottom to false', () => { - expect(stateCopy.isTraceScrolledToBottom).toEqual(false); - }); - - it('sets hasBeenScrolled to true', () => { - expect(stateCopy.hasBeenScrolled).toEqual(true); - }); - }); - - describe('SCROLL_TO_BOTTOM', () => { - beforeEach(() => { - mutations[types.SCROLL_TO_BOTTOM](stateCopy); - }); - - it('sets isTraceScrolledToBottom to true', () => { - expect(stateCopy.isTraceScrolledToBottom).toEqual(true); - }); - - it('sets hasBeenScrolled to true', () => { - expect(stateCopy.hasBeenScrolled).toEqual(true); - }); - }); - describe('REQUEST_STAGES', () => { it('sets isLoadingStages to true', () => { mutations[types.REQUEST_STAGES](stateCopy); diff --git a/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js b/spec/javascripts/pipelines/graph/job_group_dropdown_spec.js index 2b47ca236b2..24631cc1c89 100644 --- a/spec/javascripts/pipelines/graph/dropdown_job_component_spec.js +++ b/spec/javascripts/pipelines/graph/job_group_dropdown_spec.js @@ -1,12 +1,12 @@ import Vue from 'vue'; -import component from '~/pipelines/components/graph/dropdown_job_component.vue'; +import JobGroupDropdown from '~/pipelines/components/graph/job_group_dropdown.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -describe('dropdown job component', () => { - const Component = Vue.extend(component); +describe('job group dropdown component', () => { + const Component = Vue.extend(JobGroupDropdown); let vm; - const mock = { + const group = { jobs: [ { id: 4256, @@ -71,15 +71,15 @@ describe('dropdown job component', () => { }); beforeEach(() => { - vm = mountComponent(Component, { job: mock }); + vm = mountComponent(Component, { group }); }); - it('renders button with job name and size', () => { - expect(vm.$el.querySelector('button').textContent).toContain(mock.name); - expect(vm.$el.querySelector('button').textContent).toContain(mock.size); + it('renders button with group name and size', () => { + expect(vm.$el.querySelector('button').textContent).toContain(group.name); + expect(vm.$el.querySelector('button').textContent).toContain(group.size); }); it('renders dropdown with jobs', () => { - expect(vm.$el.querySelectorAll('.scrollable-menu>ul>li').length).toEqual(mock.jobs.length); + expect(vm.$el.querySelectorAll('.scrollable-menu>ul>li').length).toEqual(group.jobs.length); }); }); diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_item_spec.js index 0ae448f2ea8..88bc4676699 100644 --- a/spec/javascripts/pipelines/graph/job_component_spec.js +++ b/spec/javascripts/pipelines/graph/job_item_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import jobComponent from '~/pipelines/components/graph/job_component.vue'; +import JobItem from '~/pipelines/components/graph/job_item.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -describe('pipeline graph job component', () => { - const JobComponent = Vue.extend(jobComponent); +describe('pipeline graph job item', () => { + const JobComponent = Vue.extend(JobItem); let component; const mockJob = { diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js index f6e6bd3132e..d0b8f877d6f 100644 --- a/spec/javascripts/pipelines/graph/stage_column_component_spec.js +++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js @@ -25,17 +25,16 @@ describe('stage column component', () => { }; beforeEach(() => { - - const mockJobs = []; + const mockGroups = []; for (let i = 0; i < 3; i += 1) { const mockedJob = Object.assign({}, mockJob); mockedJob.id += i; - mockJobs.push(mockedJob); + mockGroups.push(mockedJob); } component = mountComponent(StageColumnComponent, { title: 'foo', - jobs: mockJobs, + groups: mockGroups, }); }); @@ -43,14 +42,14 @@ describe('stage column component', () => { expect(component.$el.querySelector('.stage-name').textContent.trim()).toEqual('foo'); }); - it('should render the provided jobs', () => { + it('should render the provided groups', () => { expect(component.$el.querySelectorAll('.builds-container > ul > li').length).toEqual(3); }); describe('jobId', () => { it('escapes job name', () => { component = mountComponent(StageColumnComponent, { - jobs: [ + groups: [ { id: 4259, name: '<img src=x onerror=alert(document.domain)>', @@ -64,9 +63,9 @@ describe('stage column component', () => { title: 'test', }); - expect( - component.$el.querySelector('.builds-container li').getAttribute('id'), - ).toEqual('ci-badge-<img src=x onerror=alert(document.domain)>'); + expect(component.$el.querySelector('.builds-container li').getAttribute('id')).toEqual( + 'ci-badge-<img src=x onerror=alert(document.domain)>', + ); }); }); }); diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js index f17818c17c7..43750c74b99 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js @@ -94,7 +94,7 @@ describe('Header CI Component', () => { }); it('should render sidebar toggle button', () => { - expect(vm.$el.querySelector('.js-sidebar-build-toggle')).toBeDefined(); + expect(vm.$el.querySelector('.js-sidebar-build-toggle')).not.toBeNull(); }); }); |