Commit 2d3fc0b4 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '222964-collapse-button' into 'master'

Add expandable view  to Terraform MR widget

Closes #222964

See merge request gitlab-org/gitlab!34879
parents 0d276f9d e043aa91
<script>
import { __ } from '~/locale';
import { GlButton, GlCollapse, GlIcon } from '@gitlab/ui';
/**
* Renders header section with icon and expand button
* Renders expanable content section with grey background
*/
export default {
name: 'MrWidgetExpanableSection',
components: {
GlButton,
GlCollapse,
GlIcon,
},
props: {
iconName: {
type: String,
required: false,
default: 'status_warning',
},
},
data() {
return {
contentIsVisible: false,
};
},
computed: {
collapseButtonText() {
if (this.contentIsVisible) {
return __('Collapse');
}
return __('Expand');
},
},
methods: {
updateContentVisibility() {
this.contentIsVisible = !this.contentIsVisible;
},
},
};
</script>
<template>
<div>
<div class="mr-widget-body gl-display-flex">
<span
class="gl-display-flex gl-align-items-center gl-justify-content-center append-right-default gl-align-self-start gl-mt-1"
>
<gl-icon :name="iconName" :size="24" />
</span>
<div class="gl-display-flex gl-flex-fill-1 gl-flex-direction-column gl-md-flex-direction-row">
<slot name="header"></slot>
<div>
<gl-button @click="updateContentVisibility">
{{ collapseButtonText }}
</gl-button>
</div>
</div>
</div>
<gl-collapse
:visible="contentIsVisible"
class="gl-bg-gray-10 gl-border-t-solid gl-border-gray-100 gl-border-1"
>
<slot name="content"></slot>
</gl-collapse>
</div>
</template>
<script> <script>
import { GlSkeletonLoading } from '@gitlab/ui'; import { n__ } from '~/locale';
import { GlSkeletonLoading, GlSprintf } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import MrWidgetExpanableSection from '../mr_widget_expandable_section.vue';
import Poll from '~/lib/utils/poll'; import Poll from '~/lib/utils/poll';
import TerraformPlan from './terraform_plan.vue'; import TerraformPlan from './terraform_plan.vue';
...@@ -8,6 +10,8 @@ export default { ...@@ -8,6 +10,8 @@ export default {
name: 'MRWidgetTerraformContainer', name: 'MRWidgetTerraformContainer',
components: { components: {
GlSkeletonLoading, GlSkeletonLoading,
GlSprintf,
MrWidgetExpanableSection,
TerraformPlan, TerraformPlan,
}, },
props: { props: {
...@@ -19,10 +23,43 @@ export default { ...@@ -19,10 +23,43 @@ export default {
data() { data() {
return { return {
loading: true, loading: true,
plans: {}, plansObject: {},
poll: null, poll: null,
}; };
}, },
computed: {
inValidPlanCountText() {
if (this.numberOfInvalidPlans === 0) {
return null;
}
return n__(
'Terraform|%{number} Terraform report failed to generate',
'Terraform|%{number} Terraform reports failed to generate',
this.numberOfInvalidPlans,
);
},
numberOfInvalidPlans() {
return Object.values(this.plansObject).filter(plan => plan.tf_report_error).length;
},
numberOfPlans() {
return Object.keys(this.plansObject).length;
},
numberOfValidPlans() {
return this.numberOfPlans - this.numberOfInvalidPlans;
},
validPlanCountText() {
if (this.numberOfValidPlans === 0) {
return null;
}
return n__(
'Terraform|%{number} Terraform report was generated in your pipelines',
'Terraform|%{number} Terraform reports were generated in your pipelines',
this.numberOfValidPlans,
);
},
},
created() { created() {
this.fetchPlans(); this.fetchPlans();
}, },
...@@ -40,15 +77,15 @@ export default { ...@@ -40,15 +77,15 @@ export default {
data: this.endpoint, data: this.endpoint,
method: 'fetchPlans', method: 'fetchPlans',
successCallback: ({ data }) => { successCallback: ({ data }) => {
this.plans = data; this.plansObject = data;
if (Object.keys(this.plans).length) { if (this.numberOfPlans > 0) {
this.loading = false; this.loading = false;
this.poll.stop(); this.poll.stop();
} }
}, },
errorCallback: () => { errorCallback: () => {
this.plans = { bad_plan: {} }; this.plansObject = { bad_plan: { tf_report_error: 'api_error' } };
this.loading = false; this.loading = false;
this.poll.stop(); this.poll.stop();
}, },
...@@ -62,16 +99,42 @@ export default { ...@@ -62,16 +99,42 @@ export default {
<template> <template>
<section class="mr-widget-section"> <section class="mr-widget-section">
<div v-if="loading" class="mr-widget-body media"> <div v-if="loading" class="mr-widget-body">
<gl-skeleton-loading /> <gl-skeleton-loading />
</div> </div>
<terraform-plan <mr-widget-expanable-section v-else>
v-for="(plan, key) in plans" <template #header>
v-else <div
:key="key" data-testid="terraform-header-text"
:plan="plan" class="gl-flex-fill-1 gl-display-flex gl-flex-direction-column"
class="mr-widget-body media" >
/> <p v-if="validPlanCountText" class="gl-m-0">
<gl-sprintf :message="validPlanCountText">
<template #number>
<strong>{{ numberOfValidPlans }}</strong>
</template>
</gl-sprintf>
</p>
<p v-if="inValidPlanCountText" class="gl-m-0">
<gl-sprintf :message="inValidPlanCountText">
<template #number>
<strong>{{ numberOfInvalidPlans }}</strong>
</template>
</gl-sprintf>
</p>
</div>
</template>
<template #content>
<terraform-plan
v-for="(plan, key) in plansObject"
:key="key"
:plan="plan"
class="mr-widget-body"
/>
</template>
</mr-widget-expanable-section>
</section> </section>
</template> </template>
...@@ -25,21 +25,28 @@ export default { ...@@ -25,21 +25,28 @@ export default {
deleteNum() { deleteNum() {
return Number(this.plan.delete); return Number(this.plan.delete);
}, },
iconType() {
return this.validPlanValues ? 'doc-changes' : 'warning';
},
reportChangeText() { reportChangeText() {
if (this.validPlanValues) { if (this.validPlanValues) {
return __( return __(
'Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete', 'Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete',
); );
} }
return __('Generating the report caused an error.'); return __('Terraform|Generating the report caused an error.');
}, },
reportHeaderText() { reportHeaderText() {
if (this.plan.job_name) { if (this.validPlanValues) {
return __('The Terraform report %{name} was generated in your pipelines.'); return this.plan.job_name
? __('Terraform|The Terraform report %{name} was generated in your pipelines.')
: __('Terraform|A Terraform report was generated in your pipelines.');
} }
return __('A Terraform report was generated in your pipelines.'); return this.plan.job_name
? __('Terraform|The Terraform report %{name} failed to generate.')
: __('Terraform|A Terraform report failed to generate.');
}, },
validPlanValues() { validPlanValues() {
return this.addNum + this.changeNum + this.deleteNum >= 0; return this.addNum + this.changeNum + this.deleteNum >= 0;
...@@ -53,11 +60,11 @@ export default { ...@@ -53,11 +60,11 @@ export default {
<span <span
class="gl-display-flex gl-align-items-center gl-justify-content-center append-right-default gl-align-self-start gl-mt-1" class="gl-display-flex gl-align-items-center gl-justify-content-center append-right-default gl-align-self-start gl-mt-1"
> >
<gl-icon name="status_warning" :size="24" /> <gl-icon :name="iconType" :size="18" data-testid="change-type-icon" />
</span> </span>
<div class="gl-display-flex gl-flex-fill-1 gl-flex-direction-column flex-md-row"> <div class="gl-display-flex gl-flex-fill-1 gl-flex-direction-column flex-md-row">
<div class="terraform-mr-plan-text normal gl-display-flex gl-flex-direction-column"> <div class="gl-flex-fill-1 gl-display-flex gl-flex-direction-column">
<p class="gl-m-0 gl-pr-1"> <p class="gl-m-0 gl-pr-1">
<gl-sprintf :message="reportHeaderText"> <gl-sprintf :message="reportHeaderText">
<template #name> <template #name>
...@@ -88,10 +95,11 @@ export default { ...@@ -88,10 +95,11 @@ export default {
v-if="plan.job_path" v-if="plan.job_path"
:href="plan.job_path" :href="plan.job_path"
target="_blank" target="_blank"
data-testid="terraform-report-link"
data-track-event="click_terraform_mr_plan_button" data-track-event="click_terraform_mr_plan_button"
data-track-label="mr_widget_terraform_mr_plan_button" data-track-label="mr_widget_terraform_mr_plan_button"
data-track-property="terraform_mr_plan_button" data-track-property="terraform_mr_plan_button"
class="btn btn-sm js-terraform-report-link" class="btn btn-sm"
rel="noopener" rel="noopener"
> >
{{ __('View full log') }} {{ __('View full log') }}
......
---
title: Add expand/collapse view to Terraform MR widget
merge_request: 34879
author:
type: changed
...@@ -999,9 +999,6 @@ msgstr "" ...@@ -999,9 +999,6 @@ msgstr ""
msgid "A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates." msgid "A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates."
msgstr "" msgstr ""
msgid "A Terraform report was generated in your pipelines."
msgstr ""
msgid "A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages" msgid "A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages"
msgstr "" msgstr ""
...@@ -10274,9 +10271,6 @@ msgstr "" ...@@ -10274,9 +10271,6 @@ msgstr ""
msgid "Generate new export" msgid "Generate new export"
msgstr "" msgstr ""
msgid "Generating the report caused an error."
msgstr ""
msgid "Geo" msgid "Geo"
msgstr "" msgstr ""
...@@ -19100,9 +19094,6 @@ msgstr "" ...@@ -19100,9 +19094,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}" msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "" msgstr ""
msgid "Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete"
msgstr ""
msgid "Reporter" msgid "Reporter"
msgstr "" msgstr ""
...@@ -22363,6 +22354,34 @@ msgstr "" ...@@ -22363,6 +22354,34 @@ msgstr ""
msgid "Terms of Service and Privacy Policy" msgid "Terms of Service and Privacy Policy"
msgstr "" msgstr ""
msgid "Terraform|%{number} Terraform report failed to generate"
msgid_plural "Terraform|%{number} Terraform reports failed to generate"
msgstr[0] ""
msgstr[1] ""
msgid "Terraform|%{number} Terraform report was generated in your pipelines"
msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
msgstr[0] ""
msgstr[1] ""
msgid "Terraform|A Terraform report failed to generate."
msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
msgid "Terraform|Generating the report caused an error."
msgstr ""
msgid "Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete"
msgstr ""
msgid "Terraform|The Terraform report %{name} failed to generate."
msgstr ""
msgid "Terraform|The Terraform report %{name} was generated in your pipelines."
msgstr ""
msgid "Test" msgid "Test"
msgstr "" msgstr ""
...@@ -22490,9 +22509,6 @@ msgstr "" ...@@ -22490,9 +22509,6 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}" msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "" msgstr ""
msgid "The Terraform report %{name} was generated in your pipelines."
msgstr ""
msgid "The URL defined on the primary node that secondary nodes should use to contact it." msgid "The URL defined on the primary node that secondary nodes should use to contact it."
msgstr "" msgstr ""
......
import { GlButton, GlCollapse, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_widget_expandable_section.vue';
describe('MrWidgetExpanableSection', () => {
let wrapper;
const findButton = () => wrapper.find(GlButton);
const findCollapse = () => wrapper.find(GlCollapse);
beforeEach(() => {
wrapper = shallowMount(MrCollapsibleSection, {
slots: {
content: '<span>Collapsable Content</span>',
header: '<span>Header Content</span>',
},
});
});
it('renders Icon', () => {
expect(wrapper.contains(GlIcon)).toBe(true);
});
it('renders header slot', () => {
expect(wrapper.text()).toContain('Header Content');
});
it('renders content slot', () => {
expect(wrapper.text()).toContain('Collapsable Content');
});
describe('when collapse section is closed', () => {
it('renders button with expand text', () => {
expect(findButton().text()).toBe('Expand');
});
it('renders a collpased section with no visibility', () => {
const collapse = findCollapse();
expect(collapse.exists()).toBe(true);
expect(collapse.attributes('visible')).toBeUndefined();
});
});
describe('when collapse section is open', () => {
beforeEach(() => {
findButton().vm.$emit('click');
return wrapper.vm.$nextTick();
});
it('renders button with collapse text', () => {
const button = findButton();
expect(button.exists()).toBe(true);
expect(button.text()).toBe('Collapse');
});
it('renders a collpased section with visible content', () => {
const collapse = findCollapse();
expect(collapse.exists()).toBe(true);
expect(collapse.attributes('visible')).toBe('true');
});
});
});
export const invalidPlan = {}; export const invalidPlanWithName = {
job_name: 'Invalid Plan',
job_path: '/path/to/ci/logs/1',
tf_report_error: 'api_error',
};
export const invalidPlanWithoutName = {
tf_report_error: 'invalid_json_format',
};
export const validPlanWithName = {
create: 10,
update: 20,
delete: 30,
job_name: 'Valid Plan',
job_path: '/path/to/ci/logs/1',
};
export const validPlan = { export const validPlanWithoutName = {
create: 10, create: 10,
update: 20, update: 20,
delete: 30, delete: 30,
job_name: 'Plan Changes',
job_path: '/path/to/ci/logs/1', job_path: '/path/to/ci/logs/1',
}; };
export const plans = { export const plans = {
'1': validPlan, invalid_plan_one: invalidPlanWithName,
'2': invalidPlan, invalid_plan_two: invalidPlanWithName,
'3': { valid_plan_one: validPlanWithName,
create: 1, valid_plan_two: validPlanWithoutName,
update: 2,
delete: 3,
job_name: 'Plan 3',
job_path: '/path/to/ci/logs/3',
},
}; };
import { GlSkeletonLoading } from '@gitlab/ui'; import { GlSkeletonLoading, GlSprintf } from '@gitlab/ui';
import { plans } from './mock_data'; import { invalidPlanWithName, plans, validPlanWithName } from './mock_data';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import MrWidgetExpanableSection from '~/vue_merge_request_widget/components/mr_widget_expandable_section.vue';
import MrWidgetTerraformContainer from '~/vue_merge_request_widget/components/terraform/mr_widget_terraform_container.vue'; import MrWidgetTerraformContainer from '~/vue_merge_request_widget/components/terraform/mr_widget_terraform_container.vue';
import Poll from '~/lib/utils/poll'; import Poll from '~/lib/utils/poll';
import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue'; import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue';
...@@ -13,6 +14,7 @@ describe('MrWidgetTerraformConainer', () => { ...@@ -13,6 +14,7 @@ describe('MrWidgetTerraformConainer', () => {
const propsData = { endpoint: '/path/to/terraform/report.json' }; const propsData = { endpoint: '/path/to/terraform/report.json' };
const findHeader = () => wrapper.find('[data-testid="terraform-header-text"]');
const findPlans = () => wrapper.findAll(TerraformPlan).wrappers.map(x => x.props('plan')); const findPlans = () => wrapper.findAll(TerraformPlan).wrappers.map(x => x.props('plan'));
const mockPollingApi = (response, body, header) => { const mockPollingApi = (response, body, header) => {
...@@ -20,7 +22,10 @@ describe('MrWidgetTerraformConainer', () => { ...@@ -20,7 +22,10 @@ describe('MrWidgetTerraformConainer', () => {
}; };
const mountWrapper = () => { const mountWrapper = () => {
wrapper = shallowMount(MrWidgetTerraformContainer, { propsData }); wrapper = shallowMount(MrWidgetTerraformContainer, {
propsData,
stubs: { MrWidgetExpanableSection, GlSprintf },
});
return axios.waitForAll(); return axios.waitForAll();
}; };
...@@ -44,9 +49,76 @@ describe('MrWidgetTerraformConainer', () => { ...@@ -44,9 +49,76 @@ describe('MrWidgetTerraformConainer', () => {
}); });
it('diplays loading skeleton', () => { it('diplays loading skeleton', () => {
expect(wrapper.find(GlSkeletonLoading).exists()).toBe(true); expect(wrapper.contains(GlSkeletonLoading)).toBe(true);
expect(wrapper.contains(MrWidgetExpanableSection)).toBe(false);
});
});
describe('when data has finished loading', () => {
beforeEach(() => {
mockPollingApi(200, plans, {});
return mountWrapper();
});
it('displays terraform content', () => {
expect(wrapper.contains(GlSkeletonLoading)).toBe(false);
expect(wrapper.contains(MrWidgetExpanableSection)).toBe(true);
expect(findPlans()).toEqual(Object.values(plans));
});
describe('when data includes one invalid plan', () => {
beforeEach(() => {
const invalidPlanGroup = { bad_plan: invalidPlanWithName };
mockPollingApi(200, invalidPlanGroup, {});
return mountWrapper();
});
expect(findPlans()).toEqual([]); it('displays header text for one invalid plan', () => {
expect(findHeader().text()).toBe('1 Terraform report failed to generate');
});
});
describe('when data includes multiple invalid plans', () => {
beforeEach(() => {
const invalidPlanGroup = {
bad_plan_one: invalidPlanWithName,
bad_plan_two: invalidPlanWithName,
};
mockPollingApi(200, invalidPlanGroup, {});
return mountWrapper();
});
it('displays header text for multiple invalid plans', () => {
expect(findHeader().text()).toBe('2 Terraform reports failed to generate');
});
});
describe('when data includes one valid plan', () => {
beforeEach(() => {
const validPlanGroup = { valid_plan: validPlanWithName };
mockPollingApi(200, validPlanGroup, {});
return mountWrapper();
});
it('displays header text for one valid plans', () => {
expect(findHeader().text()).toBe('1 Terraform report was generated in your pipelines');
});
});
describe('when data includes multiple valid plans', () => {
beforeEach(() => {
const validPlanGroup = {
valid_plan_one: validPlanWithName,
valid_plan_two: validPlanWithName,
};
mockPollingApi(200, validPlanGroup, {});
return mountWrapper();
});
it('displays header text for multiple valid plans', () => {
expect(findHeader().text()).toBe('2 Terraform reports were generated in your pipelines');
});
}); });
}); });
...@@ -71,12 +143,6 @@ describe('MrWidgetTerraformConainer', () => { ...@@ -71,12 +143,6 @@ describe('MrWidgetTerraformConainer', () => {
return mountWrapper(); return mountWrapper();
}); });
it('diplays terraform components and stops loading', () => {
expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false);
expect(findPlans()).toEqual(Object.values(plans));
});
it('does not make additional requests after poll is successful', () => { it('does not make additional requests after poll is successful', () => {
expect(pollRequest).toHaveBeenCalledTimes(1); expect(pollRequest).toHaveBeenCalledTimes(1);
expect(pollStop).toHaveBeenCalledTimes(1); expect(pollStop).toHaveBeenCalledTimes(1);
...@@ -90,11 +156,11 @@ describe('MrWidgetTerraformConainer', () => { ...@@ -90,11 +156,11 @@ describe('MrWidgetTerraformConainer', () => {
}); });
it('stops loading', () => { it('stops loading', () => {
expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false); expect(wrapper.contains(GlSkeletonLoading)).toBe(false);
}); });
it('generates one broken plan', () => { it('generates one broken plan', () => {
expect(findPlans()).toEqual([{}]); expect(findPlans()).toEqual([{ tf_report_error: 'api_error' }]);
}); });
it('does not make additional requests after poll is unsuccessful', () => { it('does not make additional requests after poll is unsuccessful', () => {
......
import { invalidPlan, validPlan } from './mock_data';
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue'; import TerraformPlan from '~/vue_merge_request_widget/components/terraform/terraform_plan.vue';
import {
invalidPlanWithName,
invalidPlanWithoutName,
validPlanWithName,
validPlanWithoutName,
} from './mock_data';
describe('TerraformPlan', () => { describe('TerraformPlan', () => {
let wrapper; let wrapper;
const findLogButton = () => wrapper.find('.js-terraform-report-link'); const findIcon = () => wrapper.find('[data-testid="change-type-icon"]');
const findLogButton = () => wrapper.find('[data-testid="terraform-report-link"]');
const mountWrapper = propsData => { const mountWrapper = propsData => {
wrapper = shallowMount(TerraformPlan, { stubs: { GlLink, GlSprintf }, propsData }); wrapper = shallowMount(TerraformPlan, { stubs: { GlLink, GlSprintf }, propsData });
...@@ -16,20 +22,24 @@ describe('TerraformPlan', () => { ...@@ -16,20 +22,24 @@ describe('TerraformPlan', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('validPlan', () => { describe('valid plan with job_name', () => {
beforeEach(() => { beforeEach(() => {
mountWrapper({ plan: validPlan }); mountWrapper({ plan: validPlanWithName });
}); });
it('diplays the plan job_name', () => { it('displays a document icon', () => {
expect(findIcon().attributes('name')).toBe('doc-changes');
});
it('diplays the header text with a name', () => {
expect(wrapper.text()).toContain( expect(wrapper.text()).toContain(
`The Terraform report ${validPlan.job_name} was generated in your pipelines.`, `The Terraform report ${validPlanWithName.job_name} was generated in your pipelines.`,
); );
}); });
it('diplays the reported changes', () => { it('diplays the reported changes', () => {
expect(wrapper.text()).toContain( expect(wrapper.text()).toContain(
`Reported Resource Changes: ${validPlan.create} to add, ${validPlan.update} to change, ${validPlan.delete} to delete`, `Reported Resource Changes: ${validPlanWithName.create} to add, ${validPlanWithName.update} to change, ${validPlanWithName.delete} to delete`,
); );
}); });
...@@ -39,18 +49,44 @@ describe('TerraformPlan', () => { ...@@ -39,18 +49,44 @@ describe('TerraformPlan', () => {
}); });
}); });
describe('invalidPlan', () => { describe('valid plan without job_name', () => {
beforeEach(() => { beforeEach(() => {
mountWrapper({ plan: invalidPlan }); mountWrapper({ plan: validPlanWithoutName });
}); });
it('diplays generic header since job_name is missing', () => { it('diplays the header text without a name', () => {
expect(wrapper.text()).toContain('A Terraform report was generated in your pipelines.'); expect(wrapper.text()).toContain('A Terraform report was generated in your pipelines.');
}); });
});
describe('invalid plan with job_name', () => {
beforeEach(() => {
mountWrapper({ plan: invalidPlanWithName });
});
it('displays a warning icon', () => {
expect(findIcon().attributes('name')).toBe('warning');
});
it('diplays the header text with a name', () => {
expect(wrapper.text()).toContain(
`The Terraform report ${invalidPlanWithName.job_name} failed to generate.`,
);
});
it('diplays generic error since report values are missing', () => { it('diplays generic error since report values are missing', () => {
expect(wrapper.text()).toContain('Generating the report caused an error.'); expect(wrapper.text()).toContain('Generating the report caused an error.');
}); });
});
describe('invalid plan with out job_name', () => {
beforeEach(() => {
mountWrapper({ plan: invalidPlanWithoutName });
});
it('diplays the header text without a name', () => {
expect(wrapper.text()).toContain('A Terraform report failed to generate.');
});
it('does not render button because url is missing', () => { it('does not render button because url is missing', () => {
expect(findLogButton().exists()).toBe(false); expect(findLogButton().exists()).toBe(false);
......
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