Commit bb1bd337 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '223211-refactor-job_app_spec-to-not-use-js-selectors' into 'master'

Refactor job_app not to use js-selectors

Closes #223211

See merge request gitlab-org/gitlab!37343
parents d8eebe1c ca7f684f
...@@ -71,9 +71,9 @@ export default { ...@@ -71,9 +71,9 @@ export default {
<div class="col-12"> <div class="col-12">
<div class="text-content"> <div class="text-content">
<h4 class="js-job-empty-state-title text-center">{{ title }}</h4> <h4 class="text-center" data-testid="job-empty-state-title">{{ title }}</h4>
<p v-if="content" class="js-job-empty-state-content">{{ content }}</p> <p v-if="content" data-testid="job-empty-state-content">{{ content }}</p>
</div> </div>
<manual-variables-form <manual-variables-form
v-if="shouldRenderManualVariables" v-if="shouldRenderManualVariables"
...@@ -85,7 +85,8 @@ export default { ...@@ -85,7 +85,8 @@ export default {
<gl-link <gl-link
:href="action.path" :href="action.path"
:data-method="action.method" :data-method="action.method"
class="js-job-empty-state-action btn btn-primary" class="btn btn-primary"
data-testid="job-empty-state-action"
>{{ action.button_title }}</gl-link >{{ action.button_title }}</gl-link
> >
</div> </div>
......
...@@ -198,17 +198,13 @@ export default { ...@@ -198,17 +198,13 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<gl-loading-icon <gl-loading-icon v-if="isLoading" size="lg" class="qa-loading-animation prepend-top-20" />
v-if="isLoading"
size="lg"
class="js-job-loading qa-loading-animation prepend-top-20"
/>
<template v-else-if="shouldRenderContent"> <template v-else-if="shouldRenderContent">
<div class="js-job-content build-page"> <div class="build-page" data-testid="job-content">
<!-- Header Section --> <!-- Header Section -->
<header> <header>
<div class="js-build-header build-header top-area"> <div class="build-header top-area">
<ci-header <ci-header
:status="job.status" :status="job.status"
:item-id="job.id" :item-id="job.id"
...@@ -230,7 +226,6 @@ export default { ...@@ -230,7 +226,6 @@ export default {
<!-- Body Section --> <!-- Body Section -->
<stuck-block <stuck-block
v-if="job.stuck" v-if="job.stuck"
class="js-job-stuck"
:has-no-runners-for-project="hasRunnersForProject" :has-no-runners-for-project="hasRunnersForProject"
:tags="job.tags" :tags="job.tags"
:runners-path="runnerSettingsUrl" :runners-path="runnerSettingsUrl"
...@@ -238,13 +233,11 @@ export default { ...@@ -238,13 +233,11 @@ export default {
<unmet-prerequisites-block <unmet-prerequisites-block
v-if="hasUnmetPrerequisitesFailure" v-if="hasUnmetPrerequisitesFailure"
class="js-job-failed"
:help-path="deploymentHelpUrl" :help-path="deploymentHelpUrl"
/> />
<shared-runner <shared-runner
v-if="shouldRenderSharedRunnerLimitWarning" v-if="shouldRenderSharedRunnerLimitWarning"
class="js-shared-runner-limit"
:quota-used="job.runners.quota.used" :quota-used="job.runners.quota.used"
:quota-limit="job.runners.quota.limit" :quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl" :runners-path="runnerHelpUrl"
...@@ -254,7 +247,6 @@ export default { ...@@ -254,7 +247,6 @@ export default {
<environments-block <environments-block
v-if="hasEnvironment" v-if="hasEnvironment"
class="js-job-environment"
:deployment-status="job.deployment_status" :deployment-status="job.deployment_status"
:deployment-cluster="job.deployment_cluster" :deployment-cluster="job.deployment_cluster"
:icon-status="job.status" :icon-status="job.status"
...@@ -262,7 +254,7 @@ export default { ...@@ -262,7 +254,7 @@ export default {
<erased-block <erased-block
v-if="job.erased_at" v-if="job.erased_at"
class="js-job-erased-block" data-testid="job-erased-block"
:user="job.erased_by" :user="job.erased_by"
:erased-at="job.erased_at" :erased-at="job.erased_at"
/> />
...@@ -270,8 +262,9 @@ export default { ...@@ -270,8 +262,9 @@ export default {
<div <div
v-if="job.archived" v-if="job.archived"
ref="sticky" ref="sticky"
class="js-archived-job gl-mt-3 archived-job" class="gl-mt-3 archived-job"
:class="{ 'sticky-top border-bottom-0': hasTrace }" :class="{ 'sticky-top border-bottom-0': hasTrace }"
data-testid="archived-job"
> >
<icon name="lock" class="align-text-bottom" /> <icon name="lock" class="align-text-bottom" />
{{ __('This job is archived. Only the complete pipeline can be retried.') }} {{ __('This job is archived. Only the complete pipeline can be retried.') }}
...@@ -305,7 +298,6 @@ export default { ...@@ -305,7 +298,6 @@ export default {
<!-- empty state --> <!-- empty state -->
<empty-state <empty-state
v-if="!hasTrace" v-if="!hasTrace"
class="js-job-empty-state"
:illustration-path="emptyStateIllustration.image" :illustration-path="emptyStateIllustration.image"
:illustration-size-class="emptyStateIllustration.size" :illustration-size-class="emptyStateIllustration.size"
:title="emptyStateTitle" :title="emptyStateTitle"
...@@ -323,12 +315,12 @@ export default { ...@@ -323,12 +315,12 @@ export default {
<sidebar <sidebar
v-if="shouldRenderContent" v-if="shouldRenderContent"
class="js-job-sidebar"
:class="{ :class="{
'right-sidebar-expanded': isSidebarOpen, 'right-sidebar-expanded': isSidebarOpen,
'right-sidebar-collapsed': !isSidebarOpen, 'right-sidebar-collapsed': !isSidebarOpen,
}" }"
:runner-help-url="runnerHelpUrl" :runner-help-url="runnerHelpUrl"
data-testid="job-sidebar"
/> />
</div> </div>
</template> </template>
...@@ -71,13 +71,14 @@ export default { ...@@ -71,13 +71,14 @@ export default {
<template> <template>
<div class="top-bar"> <div class="top-bar">
<!-- truncate information --> <!-- truncate information -->
<div class="js-truncated-info truncated-info d-none d-sm-block float-left"> <div class="truncated-info d-none d-sm-block float-left" data-testid="log-truncated-info">
<template v-if="isTraceSizeVisible"> <template v-if="isTraceSizeVisible">
{{ jobLogSize }} {{ jobLogSize }}
<gl-link <gl-link
v-if="rawPath" v-if="rawPath"
:href="rawPath" :href="rawPath"
class="js-raw-link text-plain text-underline gl-ml-2" class="text-plain text-underline gl-ml-2"
data-testid="raw-link"
>{{ s__('Job|Complete Raw') }}</gl-link >{{ s__('Job|Complete Raw') }}</gl-link
> >
</template> </template>
...@@ -91,7 +92,8 @@ export default { ...@@ -91,7 +92,8 @@ export default {
v-gl-tooltip.body v-gl-tooltip.body
:title="s__('Job|Show complete raw')" :title="s__('Job|Show complete raw')"
:href="rawPath" :href="rawPath"
class="js-raw-link-controller controllers-buttons" class="controllers-buttons"
data-testid="job-raw-link-controller"
> >
<icon name="doc-text" /> <icon name="doc-text" />
</gl-link> </gl-link>
...@@ -102,7 +104,8 @@ export default { ...@@ -102,7 +104,8 @@ export default {
:title="s__('Job|Erase job log')" :title="s__('Job|Erase job log')"
:href="erasePath" :href="erasePath"
:data-confirm="__('Are you sure you want to erase this build?')" :data-confirm="__('Are you sure you want to erase this build?')"
class="js-erase-link controllers-buttons" class="controllers-buttons"
data-testid="job-log-erase-link"
data-method="post" data-method="post"
> >
<icon name="remove" /> <icon name="remove" />
...@@ -114,7 +117,8 @@ export default { ...@@ -114,7 +117,8 @@ export default {
<gl-deprecated-button <gl-deprecated-button
:disabled="isScrollTopDisabled" :disabled="isScrollTopDisabled"
type="button" type="button"
class="js-scroll-top btn-scroll btn-transparent btn-blank" class="btn-scroll btn-transparent btn-blank"
data-testid="job-controller-scroll-top"
@click="handleScrollToTop" @click="handleScrollToTop"
> >
<icon name="scroll_up" /> <icon name="scroll_up" />
...@@ -126,6 +130,7 @@ export default { ...@@ -126,6 +130,7 @@ export default {
:disabled="isScrollBottomDisabled" :disabled="isScrollBottomDisabled"
class="js-scroll-bottom btn-scroll btn-transparent btn-blank" class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
:class="{ animate: isScrollingDown }" :class="{ animate: isScrollingDown }"
data-testid="job-controller-scroll-bottom"
@click="handleScrollToBottom" @click="handleScrollToBottom"
v-html="$options.scrollDown" v-html="$options.scrollDown"
/> />
......
...@@ -100,7 +100,7 @@ export default { ...@@ -100,7 +100,7 @@ export default {
}; };
</script> </script>
<template> <template>
<div class="js-manual-vars-form col-12"> <div class="col-12" data-testid="manual-vars-form">
<label>{{ s__('CiVariables|Variables') }}</label> <label>{{ s__('CiVariables|Variables') }}</label>
<div class="ci-table"> <div class="ci-table">
......
...@@ -147,7 +147,8 @@ export default { ...@@ -147,7 +147,8 @@ export default {
<gl-link <gl-link
v-if="job.new_issue_path" v-if="job.new_issue_path"
:href="job.new_issue_path" :href="job.new_issue_path"
class="js-new-issue btn btn-success btn-inverted float-left mr-2" class="btn btn-success btn-inverted float-left mr-2"
data-testid="job-new-issue"
>{{ __('New issue') }}</gl-link >{{ __('New issue') }}</gl-link
> >
<gl-link <gl-link
......
...@@ -26,22 +26,27 @@ export default { ...@@ -26,22 +26,27 @@ export default {
</script> </script>
<template> <template>
<div class="bs-callout bs-callout-warning"> <div class="bs-callout bs-callout-warning">
<p v-if="tags.length" class="js-stuck-with-tags gl-mb-0"> <p v-if="tags.length" class="gl-mb-0" data-testid="job-stuck-with-tags">
{{ {{
s__(`This job is stuck because you don't have s__(`This job is stuck because you don't have
any active runners online or available with any of these tags assigned to them:`) any active runners online or available with any of these tags assigned to them:`)
}} }}
<span v-for="(tag, index) in tags" :key="index" class="badge badge-primary gl-mr-2"> <span
v-for="(tag, index) in tags"
:key="index"
class="badge badge-primary gl-mr-2"
data-testid="badge"
>
{{ tag }} {{ tag }}
</span> </span>
</p> </p>
<p v-else-if="hasNoRunnersForProject" class="js-stuck-no-runners gl-mb-0"> <p v-else-if="hasNoRunnersForProject" class="gl-mb-0" data-testid="job-stuck-no-runners">
{{ {{
s__(`Job|This job is stuck because the project s__(`Job|This job is stuck because the project
doesn't have any runners online assigned to it.`) doesn't have any runners online assigned to it.`)
}} }}
</p> </p>
<p v-else class="js-stuck-no-active-runner gl-mb-0"> <p v-else class="gl-mb-0" data-testid="job-stuck-no-active-runners">
{{ {{
s__(`This job is stuck because you don't s__(`This job is stuck because you don't
have any active runners that can run this job.`) have any active runners that can run this job.`)
...@@ -49,7 +54,7 @@ export default { ...@@ -49,7 +54,7 @@ export default {
</p> </p>
{{ __('Go to project') }} {{ __('Go to project') }}
<gl-link v-if="runnersPath" :href="runnersPath" class="js-runners-path"> <gl-link v-if="runnersPath" :href="runnersPath">
{{ __('CI settings') }} {{ __('CI settings') }}
</gl-link> </gl-link>
</div> </div>
......
...@@ -26,7 +26,7 @@ RSpec.describe 'User browses a job', :js do ...@@ -26,7 +26,7 @@ RSpec.describe 'User browses a job', :js do
# scroll to the top of the page first # scroll to the top of the page first
execute_script "window.scrollTo(0,0)" execute_script "window.scrollTo(0,0)"
accept_confirm { find('.js-erase-link').click } accept_confirm { find('[data-testid="job-log-erase-link"]').click }
expect(page).to have_no_css('.artifacts') expect(page).to have_no_css('.artifacts')
expect(build).not_to have_trace expect(build).not_to have_trace
......
...@@ -282,7 +282,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -282,7 +282,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
href = new_project_issue_path(project, options) href = new_project_issue_path(project, options)
page.within('.build-sidebar') do page.within('.build-sidebar') do
expect(find('.js-new-issue')['href']).to include(href) expect(find('[data-testid="job-new-issue"]')['href']).to include(href)
end end
end end
end end
...@@ -425,7 +425,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -425,7 +425,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
it do it do
wait_for_all_requests wait_for_all_requests
expect(page).to have_css('.js-raw-link-controller') expect(page).to have_css('[data-testid="job-raw-link-controller"]')
end end
end end
...@@ -875,7 +875,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -875,7 +875,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job) visit project_job_path(project, job)
wait_for_requests wait_for_requests
page.within('.js-job-erased-block') do page.within('[data-testid="job-erased-block"]') do
expect(page).to have_content('Job has been erased') expect(page).to have_content('Job has been erased')
end end
end end
...@@ -888,7 +888,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -888,7 +888,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job) visit project_job_path(project, job)
wait_for_requests wait_for_requests
expect(page).not_to have_css('.js-job-erased-block') expect(page).not_to have_css('[data-testid="job-erased-block"]')
end end
end end
...@@ -901,8 +901,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -901,8 +901,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job) visit project_job_path(project, job)
wait_for_requests wait_for_requests
expect(page).to have_css('.js-job-sidebar.right-sidebar-collapsed', visible: false) expect(page).to have_css('[data-testid="job-sidebar"].right-sidebar-collapsed', visible: false)
expect(page).not_to have_css('.js-job-sidebar.right-sidebar-expanded', visible: false) expect(page).not_to have_css('[data-testid="job-sidebar"].right-sidebar-expanded', visible: false)
end end
end end
...@@ -913,8 +913,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -913,8 +913,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job) visit project_job_path(project, job)
wait_for_requests wait_for_requests
expect(page).to have_css('.js-job-sidebar.right-sidebar-expanded') expect(page).to have_css('[data-testid="job-sidebar"].right-sidebar-expanded')
expect(page).not_to have_css('.js-job-sidebar.right-sidebar-collapsed') expect(page).not_to have_css('[data-testid="job-sidebar"].right-sidebar-collapsed')
end end
end end
...@@ -929,7 +929,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -929,7 +929,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) } let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
it 'renders message about job being stuck because no runners are active' do it 'renders message about job being stuck because no runners are active' do
expect(page).to have_css('.js-stuck-no-active-runner') expect(page).to have_selector('[data-testid="job-stuck-no-active-runners"]')
expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.") expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.")
end end
end end
...@@ -939,7 +939,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -939,7 +939,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) } let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) }
it 'renders message about job being stuck because of no runners with the specified tags' do it 'renders message about job being stuck because of no runners with the specified tags' do
expect(page).to have_css('.js-stuck-with-tags') expect(page).to have_selector('[data-testid="job-stuck-with-tags"')
expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:") expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:")
end end
end end
...@@ -949,7 +949,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -949,7 +949,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) } let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) }
it 'renders message about job being stuck because of no runners with the specified tags' do it 'renders message about job being stuck because of no runners with the specified tags' do
expect(page).to have_css('.js-stuck-with-tags') expect(page).to have_selector('[data-testid="job-stuck-with-tags"')
expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:") expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:")
end end
end end
...@@ -957,8 +957,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -957,8 +957,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
context 'without any runners available' do context 'without any runners available' do
let(:job) { create(:ci_build, :pending, pipeline: pipeline) } let(:job) { create(:ci_build, :pending, pipeline: pipeline) }
it 'renders message about job being stuck because not runners are available' do it 'renders message about job being stuck because no runners are available' do
expect(page).to have_css('.js-stuck-no-active-runner') expect(page).to have_selector('[data-testid="job-stuck-no-active-runners"]')
expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.") expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.")
end end
end end
...@@ -968,7 +968,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -968,7 +968,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) } let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
it 'renders message about job being stuck because runners are offline' do it 'renders message about job being stuck because runners are offline' do
expect(page).to have_css('.js-stuck-no-runners') expect(page).to have_selector('[data-testid="job-stuck-no-runners"')
expect(page).to have_content("This job is stuck because the project doesn't have any runners online assigned to it.") expect(page).to have_content("This job is stuck because the project doesn't have any runners online assigned to it.")
end end
end end
......
import Vue from 'vue'; import { mount } from '@vue/test-utils';
import component from '~/jobs/components/empty_state.vue'; import EmptyState from '~/jobs/components/empty_state.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('Empty State', () => { describe('Empty State', () => {
const Component = Vue.extend(component); let wrapper;
let vm;
const props = { const defaultProps = {
illustrationPath: 'illustrations/pending_job_empty.svg', illustrationPath: 'illustrations/pending_job_empty.svg',
illustrationSizeClass: 'svg-430', illustrationSizeClass: 'svg-430',
title: 'This job has not started yet', title: 'This job has not started yet',
...@@ -14,100 +12,107 @@ describe('Empty State', () => { ...@@ -14,100 +12,107 @@ describe('Empty State', () => {
variablesSettingsUrl: '', variablesSettingsUrl: '',
}; };
const createWrapper = props => {
wrapper = mount(EmptyState, {
propsData: {
...defaultProps,
...props,
},
});
};
const content = 'This job is in pending state and is waiting to be picked by a runner'; const content = 'This job is in pending state and is waiting to be picked by a runner';
const findEmptyStateImage = () => wrapper.find('img');
const findTitle = () => wrapper.find('[data-testid="job-empty-state-title"]');
const findContent = () => wrapper.find('[data-testid="job-empty-state-content"]');
const findAction = () => wrapper.find('[data-testid="job-empty-state-action"]');
const findManualVarsForm = () => wrapper.find('[data-testid="manual-vars-form"]');
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper?.destroy) {
wrapper.destroy();
wrapper = null;
}
}); });
describe('renders image and title', () => { describe('renders image and title', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper();
...props,
content,
});
}); });
it('renders img with provided path and size', () => { it('renders empty state image', () => {
expect(vm.$el.querySelector('img').getAttribute('src')).toEqual(props.illustrationPath); expect(findEmptyStateImage().exists()).toBe(true);
expect(vm.$el.querySelector('.svg-content').classList).toContain(props.illustrationSizeClass);
}); });
it('renders provided title', () => { it('renders provided title', () => {
expect(vm.$el.querySelector('.js-job-empty-state-title').textContent.trim()).toEqual( expect(
props.title, findTitle()
); .text()
.trim(),
).toBe(defaultProps.title);
}); });
}); });
describe('with content', () => { describe('with content', () => {
it('renders content', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({ content });
...props,
content,
}); });
expect(vm.$el.querySelector('.js-job-empty-state-content').textContent.trim()).toEqual( it('renders content', () => {
content, expect(
); findContent()
.text()
.trim(),
).toBe(content);
}); });
}); });
describe('without content', () => { describe('without content', () => {
it('does not render content', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper();
...props,
}); });
expect(vm.$el.querySelector('.js-job-empty-state-content')).toBeNull(); it('does not render content', () => {
expect(findContent().exists()).toBe(false);
}); });
}); });
describe('with action', () => { describe('with action', () => {
it('renders action', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
...props,
content,
action: { action: {
path: 'runner', path: 'runner',
button_title: 'Check runner', button_title: 'Check runner',
method: 'post', method: 'post',
}, },
}); });
});
expect(vm.$el.querySelector('.js-job-empty-state-action').getAttribute('href')).toEqual( it('renders action', () => {
'runner', expect(findAction().attributes('href')).toBe('runner');
);
}); });
}); });
describe('without action', () => { describe('without action', () => {
it('does not render action', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
...props,
content,
action: null, action: null,
}); });
expect(vm.$el.querySelector('.js-job-empty-state-action')).toBeNull();
});
}); });
describe('without playbale action', () => { it('does not render action', () => {
it('does not render manual variables form', () => { expect(findAction().exists()).toBe(false);
vm = mountComponent(Component, {
...props,
content,
}); });
expect(vm.$el.querySelector('.js-manual-vars-form')).toBeNull(); it('does not render manual variables form', () => {
expect(findManualVarsForm().exists()).toBe(false);
}); });
}); });
describe('with playbale action and not scheduled job', () => { describe('with playable action and not scheduled job', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
...props,
content, content,
playable: true, playable: true,
scheduled: false, scheduled: false,
...@@ -120,22 +125,25 @@ describe('Empty State', () => { ...@@ -120,22 +125,25 @@ describe('Empty State', () => {
}); });
it('renders manual variables form', () => { it('renders manual variables form', () => {
expect(vm.$el.querySelector('.js-manual-vars-form')).not.toBeNull(); expect(findManualVarsForm().exists()).toBe(true);
}); });
it('does not render the empty state action', () => { it('does not render the empty state action', () => {
expect(vm.$el.querySelector('.js-job-empty-state-action')).toBeNull(); expect(findAction().exists()).toBe(false);
}); });
}); });
describe('with playbale action and scheduled job', () => { describe('with playable action and scheduled job', () => {
it('does not render manual variables form', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
...props, playable: true,
scheduled: true,
content, content,
}); });
});
expect(vm.$el.querySelector('.js-manual-vars-form')).toBeNull(); it('does not render manual variables form', () => {
expect(findManualVarsForm().exists()).toBe(false);
}); });
}); });
}); });
import Vuex from 'vuex'; import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import { GlLoadingIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { getJSONFixture } from 'helpers/fixtures'; import { getJSONFixture } from 'helpers/fixtures';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import JobApp from '~/jobs/components/job_app.vue'; import JobApp from '~/jobs/components/job_app.vue';
import Sidebar from '~/jobs/components/sidebar.vue';
import StuckBlock from '~/jobs/components/stuck_block.vue';
import UnmetPrerequisitesBlock from '~/jobs/components/unmet_prerequisites_block.vue';
import EnvironmentsBlock from '~/jobs/components/environments_block.vue';
import ErasedBlock from '~/jobs/components/erased_block.vue';
import EmptyState from '~/jobs/components/empty_state.vue';
import createStore from '~/jobs/store'; import createStore from '~/jobs/store';
import job from '../mock_data'; import job from '../mock_data';
import { TEST_HOST } from 'jest/helpers/test_constants'; import { TEST_HOST } from 'jest/helpers/test_constants';
...@@ -55,6 +62,26 @@ describe('Job App', () => { ...@@ -55,6 +62,26 @@ describe('Job App', () => {
.then(() => wrapper.vm.$nextTick()); .then(() => wrapper.vm.$nextTick());
}; };
const findLoadingComponent = () => wrapper.find(GlLoadingIcon);
const findSidebar = () => wrapper.find(Sidebar);
const findJobContent = () => wrapper.find('[data-testid="job-content"');
const findStuckBlockComponent = () => wrapper.find(StuckBlock);
const findStuckBlockWithTags = () => wrapper.find('[data-testid="job-stuck-with-tags"');
const findStuckBlockNoActiveRunners = () =>
wrapper.find('[data-testid="job-stuck-no-active-runners"');
const findFailedJobComponent = () => wrapper.find(UnmetPrerequisitesBlock);
const findEnvironmentsBlockComponent = () => wrapper.find(EnvironmentsBlock);
const findErasedBlock = () => wrapper.find(ErasedBlock);
const findArchivedJob = () => wrapper.find('[data-testid="archived-job"]');
const findEmptyState = () => wrapper.find(EmptyState);
const findJobNewIssueLink = () => wrapper.find('[data-testid="job-new-issue"]');
const findJobEmptyStateTitle = () => wrapper.find('[data-testid="job-empty-state-title"]');
const findJobTraceScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]');
const findJobTraceScrollBottom = () =>
wrapper.find('[data-testid="job-controller-scroll-bottom"]');
const findJobTraceController = () => wrapper.find('[data-testid="job-raw-link-controller"]');
const findJobTraceEraseLink = () => wrapper.find('[data-testid="job-log-erase-link"]');
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
store = createStore(); store = createStore();
...@@ -72,9 +99,9 @@ describe('Job App', () => { ...@@ -72,9 +99,9 @@ describe('Job App', () => {
}); });
it('renders loading icon', () => { it('renders loading icon', () => {
expect(wrapper.find('.js-job-loading').exists()).toBe(true); expect(findLoadingComponent().exists()).toBe(true);
expect(wrapper.find('.js-job-sidebar').exists()).toBe(false); expect(findSidebar().exists()).toBe(false);
expect(wrapper.find('.js-job-content').exists()).toBe(false); expect(findJobContent().exists()).toBe(false);
}); });
}); });
...@@ -115,7 +142,7 @@ describe('Job App', () => { ...@@ -115,7 +142,7 @@ describe('Job App', () => {
}); });
it('should render new issue link', () => { it('should render new issue link', () => {
expect(wrapper.find('.js-new-issue').attributes('href')).toEqual(job.new_issue_path); expect(findJobNewIssueLink().attributes('href')).toEqual(job.new_issue_path);
}); });
}); });
...@@ -134,7 +161,7 @@ describe('Job App', () => { ...@@ -134,7 +161,7 @@ describe('Job App', () => {
}); });
describe('stuck block', () => { describe('stuck block', () => {
describe('without active runners availabl', () => { describe('without active runners available', () => {
it('renders stuck block when there are no runners', () => it('renders stuck block when there are no runners', () =>
setupAndMount({ setupAndMount({
jobData: { jobData: {
...@@ -153,8 +180,8 @@ describe('Job App', () => { ...@@ -153,8 +180,8 @@ describe('Job App', () => {
tags: [], tags: [],
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-stuck').exists()).toBe(true); expect(findStuckBlockComponent().exists()).toBe(true);
expect(wrapper.find('.js-job-stuck .js-stuck-no-active-runner').exists()).toBe(true); expect(findStuckBlockNoActiveRunners().exists()).toBe(true);
})); }));
}); });
...@@ -176,8 +203,8 @@ describe('Job App', () => { ...@@ -176,8 +203,8 @@ describe('Job App', () => {
}, },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-stuck').text()).toContain(job.tags[0]); expect(findStuckBlockComponent().text()).toContain(job.tags[0]);
expect(wrapper.find('.js-job-stuck .js-stuck-with-tags').exists()).toBe(true); expect(findStuckBlockWithTags().exists()).toBe(true);
})); }));
}); });
...@@ -199,8 +226,8 @@ describe('Job App', () => { ...@@ -199,8 +226,8 @@ describe('Job App', () => {
}, },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-stuck').text()).toContain(job.tags[0]); expect(findStuckBlockComponent().text()).toContain(job.tags[0]);
expect(wrapper.find('.js-job-stuck .js-stuck-with-tags').exists()).toBe(true); expect(findStuckBlockWithTags().exists()).toBe(true);
})); }));
}); });
...@@ -210,7 +237,7 @@ describe('Job App', () => { ...@@ -210,7 +237,7 @@ describe('Job App', () => {
runners: { available: true }, runners: { available: true },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-stuck').exists()).toBe(false); expect(findStuckBlockComponent().exists()).toBe(false);
})); }));
}); });
...@@ -239,7 +266,7 @@ describe('Job App', () => { ...@@ -239,7 +266,7 @@ describe('Job App', () => {
tags: [], tags: [],
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-failed').exists()).toBe(true); expect(findFailedJobComponent().exists()).toBe(true);
})); }));
}); });
...@@ -255,12 +282,12 @@ describe('Job App', () => { ...@@ -255,12 +282,12 @@ describe('Job App', () => {
}, },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-environment').exists()).toBe(true); expect(findEnvironmentsBlockComponent().exists()).toBe(true);
})); }));
it('does not render environment block when job has environment', () => it('does not render environment block when job has environment', () =>
setupAndMount().then(() => { setupAndMount().then(() => {
expect(wrapper.find('.js-job-environment').exists()).toBe(false); expect(findEnvironmentsBlockComponent().exists()).toBe(false);
})); }));
}); });
...@@ -275,7 +302,7 @@ describe('Job App', () => { ...@@ -275,7 +302,7 @@ describe('Job App', () => {
erased_at: '2016-11-07T11:11:16.525Z', erased_at: '2016-11-07T11:11:16.525Z',
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-erased-block').exists()).toBe(true); expect(findErasedBlock().exists()).toBe(true);
})); }));
it('does not render erased block when `erased` is false', () => it('does not render erased block when `erased` is false', () =>
...@@ -284,7 +311,7 @@ describe('Job App', () => { ...@@ -284,7 +311,7 @@ describe('Job App', () => {
erased_at: null, erased_at: null,
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-erased-block').exists()).toBe(false); expect(findErasedBlock().exists()).toBe(false);
})); }));
}); });
...@@ -313,7 +340,7 @@ describe('Job App', () => { ...@@ -313,7 +340,7 @@ describe('Job App', () => {
}, },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-empty-state').exists()).toBe(true); expect(findEmptyState().exists()).toBe(true);
})); }));
it('does not render empty state when job does not have trace but it is running', () => it('does not render empty state when job does not have trace but it is running', () =>
...@@ -329,12 +356,12 @@ describe('Job App', () => { ...@@ -329,12 +356,12 @@ describe('Job App', () => {
}, },
}, },
}).then(() => { }).then(() => {
expect(wrapper.find('.js-job-empty-state').exists()).toBe(false); expect(findEmptyState().exists()).toBe(false);
})); }));
it('does not render empty state when job has trace but it is not running', () => it('does not render empty state when job has trace but it is not running', () =>
setupAndMount({ jobData: { has_trace: true } }).then(() => { setupAndMount({ jobData: { has_trace: true } }).then(() => {
expect(wrapper.find('.js-job-empty-state').exists()).toBe(false); expect(findEmptyState().exists()).toBe(false);
})); }));
it('displays remaining time for a delayed job', () => { it('displays remaining time for a delayed job', () => {
...@@ -345,9 +372,9 @@ describe('Job App', () => { ...@@ -345,9 +372,9 @@ describe('Job App', () => {
() => new Date(delayedJobFixture.scheduled_at).getTime() - oneHourInMilliseconds, () => new Date(delayedJobFixture.scheduled_at).getTime() - oneHourInMilliseconds,
); );
return setupAndMount({ jobData: delayedJobFixture }).then(() => { return setupAndMount({ jobData: delayedJobFixture }).then(() => {
expect(wrapper.find('.js-job-empty-state').exists()).toBe(true); expect(findEmptyState().exists()).toBe(true);
const title = wrapper.find('.js-job-empty-state-title').text(); const title = findJobEmptyStateTitle().text();
expect(title).toEqual('This is a delayed job to run in 01:00:00'); expect(title).toEqual('This is a delayed job to run in 01:00:00');
}); });
...@@ -386,7 +413,7 @@ describe('Job App', () => { ...@@ -386,7 +413,7 @@ describe('Job App', () => {
beforeEach(() => setupAndMount({ jobData: { archived: true } })); beforeEach(() => setupAndMount({ jobData: { archived: true } }));
it('renders warning about job being archived', () => { it('renders warning about job being archived', () => {
expect(wrapper.find('.js-archived-job ').exists()).toBe(true); expect(findArchivedJob().exists()).toBe(true);
}); });
}); });
...@@ -394,7 +421,7 @@ describe('Job App', () => { ...@@ -394,7 +421,7 @@ describe('Job App', () => {
beforeEach(() => setupAndMount()); beforeEach(() => setupAndMount());
it('does not warning about job being archived', () => { it('does not warning about job being archived', () => {
expect(wrapper.find('.js-archived-job ').exists()).toBe(false); expect(findArchivedJob().exists()).toBe(false);
}); });
}); });
...@@ -413,16 +440,16 @@ describe('Job App', () => { ...@@ -413,16 +440,16 @@ describe('Job App', () => {
); );
it('should render scroll buttons', () => { it('should render scroll buttons', () => {
expect(wrapper.find('.js-scroll-top').exists()).toBe(true); expect(findJobTraceScrollTop().exists()).toBe(true);
expect(wrapper.find('.js-scroll-bottom').exists()).toBe(true); expect(findJobTraceScrollBottom().exists()).toBe(true);
}); });
it('should render link to raw ouput', () => { it('should render link to raw ouput', () => {
expect(wrapper.find('.js-raw-link-controller').exists()).toBe(true); expect(findJobTraceController().exists()).toBe(true);
}); });
it('should render link to erase job', () => { it('should render link to erase job', () => {
expect(wrapper.find('.js-erase-link').exists()).toBe(true); expect(findJobTraceEraseLink().exists()).toBe(true);
}); });
}); });
}); });
import Vue from 'vue'; import { mount } from '@vue/test-utils';
import component from '~/jobs/components/job_log_controllers.vue'; import JobLogControllers from '~/jobs/components/job_log_controllers.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('Job log controllers', () => { describe('Job log controllers', () => {
const Component = Vue.extend(component); let wrapper;
let vm;
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper?.destroy) {
wrapper.destroy();
wrapper = null;
}
}); });
const props = { const defaultProps = {
rawPath: '/raw', rawPath: '/raw',
erasePath: '/erase', erasePath: '/erase',
size: 511952, size: 511952,
...@@ -20,70 +21,80 @@ describe('Job log controllers', () => { ...@@ -20,70 +21,80 @@ describe('Job log controllers', () => {
isTraceSizeVisible: true, isTraceSizeVisible: true,
}; };
const createWrapper = props => {
wrapper = mount(JobLogControllers, {
propsData: {
...defaultProps,
...props,
},
});
};
const findTruncatedInfo = () => wrapper.find('[data-testid="log-truncated-info"]');
const findRawLink = () => wrapper.find('[data-testid="raw-link"]');
const findRawLinkController = () => wrapper.find('[data-testid="job-raw-link-controller"]');
const findEraseLink = () => wrapper.find('[data-testid="job-log-erase-link"]');
const findScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]');
const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]');
describe('Truncate information', () => { describe('Truncate information', () => {
describe('with isTraceSizeVisible', () => { describe('with isTraceSizeVisible', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper();
}); });
it('renders size information', () => { it('renders size information', () => {
expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB'); expect(findTruncatedInfo().text()).toMatch('499.95 KiB');
}); });
it('renders link to raw trace', () => { it('renders link to raw trace', () => {
expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw'); expect(findRawLink().attributes('href')).toBe(defaultProps.rawPath);
}); });
}); });
}); });
describe('links section', () => { describe('links section', () => {
describe('with raw trace path', () => { describe('with raw trace path', () => {
it('renders raw trace link', () => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper();
});
expect(vm.$el.querySelector('.js-raw-link-controller').getAttribute('href')).toEqual( it('renders raw trace link', () => {
'/raw', expect(findRawLinkController().attributes('href')).toBe(defaultProps.rawPath);
);
}); });
}); });
describe('without raw trace path', () => { describe('without raw trace path', () => {
it('does not render raw trace link', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
erasePath: '/erase', rawPath: null,
size: 511952, });
isScrollTopDisabled: true,
isScrollBottomDisabled: true,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
expect(vm.$el.querySelector('.js-raw-link-controller')).toBeNull(); it('does not render raw trace link', () => {
expect(findRawLinkController().exists()).toBe(false);
}); });
}); });
describe('when is erasable', () => { describe('when is erasable', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper();
}); });
it('renders erase job link', () => { it('renders erase job link', () => {
expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull(); expect(findEraseLink().exists()).toBe(true);
}); });
}); });
describe('when it is not erasable', () => { describe('when it is not erasable', () => {
it('does not render erase button', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
rawPath: '/raw', erasePath: null,
size: 511952, });
isScrollTopDisabled: true,
isScrollBottomDisabled: true,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
expect(vm.$el.querySelector('.js-erase-link')).toBeNull(); it('does not render erase button', () => {
expect(findEraseLink().exists()).toBe(false);
}); });
}); });
}); });
...@@ -92,45 +103,39 @@ describe('Job log controllers', () => { ...@@ -92,45 +103,39 @@ describe('Job log controllers', () => {
describe('scroll top button', () => { describe('scroll top button', () => {
describe('when user can scroll top', () => { describe('when user can scroll top', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper({
isScrollTopDisabled: false,
}); });
it('renders enabled scroll top button', () => {
expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toBeNull();
}); });
it('emits scrollJobLogTop event on click', () => { it('emits scrollJobLogTop event on click', async () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {}); findScrollTop().trigger('click');
vm.$el.querySelector('.js-scroll-top').click();
await wrapper.vm.$nextTick();
expect(vm.$emit).toHaveBeenCalledWith('scrollJobLogTop'); expect(wrapper.emitted().scrollJobLogTop).toHaveLength(1);
}); });
}); });
describe('when user can not scroll top', () => { describe('when user can not scroll top', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
rawPath: '/raw',
erasePath: '/erase',
size: 511952,
isScrollTopDisabled: true, isScrollTopDisabled: true,
isScrollBottomDisabled: false, isScrollBottomDisabled: false,
isScrollingDown: false, isScrollingDown: false,
isTraceSizeVisible: true,
}); });
}); });
it('renders disabled scroll top button', () => { it('renders disabled scroll top button', () => {
expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toEqual( expect(findScrollTop().attributes('disabled')).toBe('disabled');
'disabled',
);
}); });
it('does not emit scrollJobLogTop event on click', () => { it('does not emit scrollJobLogTop event on click', async () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {}); findScrollTop().trigger('click');
vm.$el.querySelector('.js-scroll-top').click();
await wrapper.vm.$nextTick();
expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogTop'); expect(wrapper.emitted().scrollJobLogTop).toBeUndefined();
}); });
}); });
}); });
...@@ -138,69 +143,61 @@ describe('Job log controllers', () => { ...@@ -138,69 +143,61 @@ describe('Job log controllers', () => {
describe('scroll bottom button', () => { describe('scroll bottom button', () => {
describe('when user can scroll bottom', () => { describe('when user can scroll bottom', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper();
}); });
it('renders enabled scroll bottom button', () => { it('emits scrollJobLogBottom event on click', async () => {
expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toBeNull(); findScrollBottom().trigger('click');
});
it('emits scrollJobLogBottom event on click', () => { await wrapper.vm.$nextTick();
jest.spyOn(vm, '$emit').mockImplementation(() => {});
vm.$el.querySelector('.js-scroll-bottom').click();
expect(vm.$emit).toHaveBeenCalledWith('scrollJobLogBottom'); expect(wrapper.emitted().scrollJobLogBottom).toHaveLength(1);
}); });
}); });
describe('when user can not scroll bottom', () => { describe('when user can not scroll bottom', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
rawPath: '/raw',
erasePath: '/erase',
size: 511952,
isScrollTopDisabled: false, isScrollTopDisabled: false,
isScrollBottomDisabled: true, isScrollBottomDisabled: true,
isScrollingDown: false, isScrollingDown: false,
isTraceSizeVisible: true,
}); });
}); });
it('renders disabled scroll bottom button', () => { it('renders disabled scroll bottom button', () => {
expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toEqual( expect(findScrollBottom().attributes('disabled')).toEqual('disabled');
'disabled',
);
}); });
it('does not emit scrollJobLogBottom event on click', () => { it('does not emit scrollJobLogBottom event on click', async () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {}); findScrollBottom().trigger('click');
vm.$el.querySelector('.js-scroll-bottom').click();
expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogBottom'); await wrapper.vm.$nextTick();
expect(wrapper.emitted().scrollJobLogBottom).toBeUndefined();
}); });
}); });
describe('while isScrollingDown is true', () => { describe('while isScrollingDown is true', () => {
it('renders animate class for the scroll down button', () => { beforeEach(() => {
vm = mountComponent(Component, props); createWrapper();
});
expect(vm.$el.querySelector('.js-scroll-bottom').className).toContain('animate'); it('renders animate class for the scroll down button', () => {
expect(findScrollBottom().classes()).toContain('animate');
}); });
}); });
describe('while isScrollingDown is false', () => { describe('while isScrollingDown is false', () => {
it('does not render animate class for the scroll down button', () => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
rawPath: '/raw',
erasePath: '/erase',
size: 511952,
isScrollTopDisabled: true, isScrollTopDisabled: true,
isScrollBottomDisabled: false, isScrollBottomDisabled: false,
isScrollingDown: false, isScrollingDown: false,
isTraceSizeVisible: true, });
}); });
expect(vm.$el.querySelector('.js-scroll-bottom').className).not.toContain('animate'); it('does not render animate class for the scroll down button', () => {
expect(findScrollBottom().classes()).not.toContain('animate');
}); });
}); });
}); });
......
...@@ -59,11 +59,13 @@ describe('Sidebar details block', () => { ...@@ -59,11 +59,13 @@ describe('Sidebar details block', () => {
describe('actions', () => { describe('actions', () => {
it('should render link to new issue', () => { it('should render link to new issue', () => {
expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( expect(vm.$el.querySelector('[data-testid="job-new-issue"]').getAttribute('href')).toEqual(
job.new_issue_path, job.new_issue_path,
); );
expect(vm.$el.querySelector('.js-new-issue').textContent.trim()).toEqual('New issue'); expect(vm.$el.querySelector('[data-testid="job-new-issue"]').textContent.trim()).toEqual(
'New issue',
);
}); });
it('should render link to retry job', () => { it('should render link to retry job', () => {
......
import Vue from 'vue'; import { GlLink } from '@gitlab/ui';
import component from '~/jobs/components/stuck_block.vue'; import { shallowMount } from '@vue/test-utils';
import mountComponent from '../../helpers/vue_mount_component_helper'; import StuckBlock from '~/jobs/components/stuck_block.vue';
describe('Stuck Block Job component', () => { describe('Stuck Block Job component', () => {
const Component = Vue.extend(component); let wrapper;
let vm;
afterEach(() => { afterEach(() => {
vm.$destroy(); if (wrapper?.destroy) {
wrapper.destroy();
wrapper = null;
}
}); });
const createWrapper = props => {
wrapper = shallowMount(StuckBlock, {
propsData: {
...props,
},
});
};
const tags = ['docker', 'gitlab-org'];
const findStuckNoActiveRunners = () =>
wrapper.find('[data-testid="job-stuck-no-active-runners"]');
const findStuckNoRunners = () => wrapper.find('[data-testid="job-stuck-no-runners"]');
const findStuckWithTags = () => wrapper.find('[data-testid="job-stuck-with-tags"]');
const findRunnerPathLink = () => wrapper.find(GlLink);
const findAllBadges = () => wrapper.findAll('[data-testid="badge"]');
describe('with no runners for project', () => { describe('with no runners for project', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
hasNoRunnersForProject: true, hasNoRunnersForProject: true,
runnersPath: '/root/project/runners#js-runners-settings', runnersPath: '/root/project/runners#js-runners-settings',
}); });
}); });
it('renders only information about project not having runners', () => { it('renders only information about project not having runners', () => {
expect(vm.$el.querySelector('.js-stuck-no-runners')).not.toBeNull(); expect(findStuckNoRunners().exists()).toBe(true);
expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); expect(findStuckWithTags().exists()).toBe(false);
expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); expect(findStuckNoActiveRunners().exists()).toBe(false);
}); });
it('renders link to runners page', () => { it('renders link to runners page', () => {
expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( expect(findRunnerPathLink().attributes('href')).toBe(
'/root/project/runners#js-runners-settings', '/root/project/runners#js-runners-settings',
); );
}); });
...@@ -33,26 +52,27 @@ describe('Stuck Block Job component', () => { ...@@ -33,26 +52,27 @@ describe('Stuck Block Job component', () => {
describe('with tags', () => { describe('with tags', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
hasNoRunnersForProject: false, hasNoRunnersForProject: false,
tags: ['docker', 'gitlab-org'], tags,
runnersPath: '/root/project/runners#js-runners-settings', runnersPath: '/root/project/runners#js-runners-settings',
}); });
}); });
it('renders information about the tags not being set', () => { it('renders information about the tags not being set', () => {
expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); expect(findStuckWithTags().exists()).toBe(true);
expect(vm.$el.querySelector('.js-stuck-with-tags')).not.toBeNull(); expect(findStuckNoActiveRunners().exists()).toBe(false);
expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); expect(findStuckNoRunners().exists()).toBe(false);
}); });
it('renders tags', () => { it('renders tags', () => {
expect(vm.$el.textContent).toContain('docker'); findAllBadges().wrappers.forEach((badgeElt, index) => {
expect(vm.$el.textContent).toContain('gitlab-org'); return expect(badgeElt.text()).toBe(tags[index]);
});
}); });
it('renders link to runners page', () => { it('renders link to runners page', () => {
expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( expect(findRunnerPathLink().attributes('href')).toBe(
'/root/project/runners#js-runners-settings', '/root/project/runners#js-runners-settings',
); );
}); });
...@@ -60,20 +80,20 @@ describe('Stuck Block Job component', () => { ...@@ -60,20 +80,20 @@ describe('Stuck Block Job component', () => {
describe('without active runners', () => { describe('without active runners', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { createWrapper({
hasNoRunnersForProject: false, hasNoRunnersForProject: false,
runnersPath: '/root/project/runners#js-runners-settings', runnersPath: '/root/project/runners#js-runners-settings',
}); });
}); });
it('renders information about project not having runners', () => { it('renders information about project not having runners', () => {
expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); expect(findStuckNoActiveRunners().exists()).toBe(true);
expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); expect(findStuckNoRunners().exists()).toBe(false);
expect(vm.$el.querySelector('.js-stuck-no-active-runner')).not.toBeNull(); expect(findStuckWithTags().exists()).toBe(false);
}); });
it('renders link to runners page', () => { it('renders link to runners page', () => {
expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( expect(findRunnerPathLink().attributes('href')).toBe(
'/root/project/runners#js-runners-settings', '/root/project/runners#js-runners-settings',
); );
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment