Commit bc78d76e authored by Savas Vedova's avatar Savas Vedova Committed by Peter Hegman

Split up yaml and humanized policy previews

The policy preview tabs were confusing for the users. For that reason,
they are split up. The right column now displays only the yaml preview
and the humanized policy preview is displayed at the bottom of the page.

Changelog: changed
EE: true
parent c3b4ef1a
...@@ -7,6 +7,9 @@ import { ...@@ -7,6 +7,9 @@ import {
GlToggle, GlToggle,
GlButton, GlButton,
GlAlert, GlAlert,
GlIcon,
GlCollapse,
GlCollapseToggleDirective,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import { removeUnnecessaryDashes } from 'ee/threat_monitoring/utils'; import { removeUnnecessaryDashes } from 'ee/threat_monitoring/utils';
...@@ -17,7 +20,7 @@ import DimDisableContainer from '../dim_disable_container.vue'; ...@@ -17,7 +20,7 @@ import DimDisableContainer from '../dim_disable_container.vue';
import PolicyActionPicker from '../policy_action_picker.vue'; import PolicyActionPicker from '../policy_action_picker.vue';
import PolicyAlertPicker from '../policy_alert_picker.vue'; import PolicyAlertPicker from '../policy_alert_picker.vue';
import PolicyEditorLayout from '../policy_editor_layout.vue'; import PolicyEditorLayout from '../policy_editor_layout.vue';
import PolicyPreview from '../policy_preview.vue'; import PolicyPreviewHuman from '../policy_preview_human.vue';
import { import {
DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY,
RuleTypeEndpoint, RuleTypeEndpoint,
...@@ -45,12 +48,14 @@ export default { ...@@ -45,12 +48,14 @@ export default {
'NetworkPolicies|Network Policies can be used to limit which network traffic is allowed between containers inside the cluster.', 'NetworkPolicies|Network Policies can be used to limit which network traffic is allowed between containers inside the cluster.',
), ),
noEnvironmentButton: __('Learn more'), noEnvironmentButton: __('Learn more'),
yamlPreview: s__('SecurityOrchestration|.yaml preview'),
policyPreview: s__('SecurityOrchestration|Policy preview'), policyPreview: s__('SecurityOrchestration|Policy preview'),
rules: s__('SecurityOrchestration|Rules'), rules: s__('SecurityOrchestration|Rules'),
saveButtonTooltip: s__( saveButtonTooltip: s__(
'NetworkPolicies|Network policy can be created after the environment is loaded successfully.', 'NetworkPolicies|Network policy can be created after the environment is loaded successfully.',
), ),
}, },
policyPreviewHumanCollapseId: 'policy-preview-human-collapse',
components: { components: {
GlEmptyState, GlEmptyState,
GlFormGroup, GlFormGroup,
...@@ -59,13 +64,18 @@ export default { ...@@ -59,13 +64,18 @@ export default {
GlToggle, GlToggle,
GlButton, GlButton,
GlAlert, GlAlert,
GlIcon,
GlCollapse,
PolicyRuleBuilder, PolicyRuleBuilder,
PolicyPreview,
PolicyActionPicker, PolicyActionPicker,
PolicyAlertPicker, PolicyAlertPicker,
PolicyEditorLayout, PolicyEditorLayout,
PolicyPreviewHuman,
DimDisableContainer, DimDisableContainer,
}, },
directives: {
CollapseToggle: GlCollapseToggleDirective,
},
inject: [ inject: [
'networkDocumentationPath', 'networkDocumentationPath',
'policyEditorEmptyStateSvgPath', 'policyEditorEmptyStateSvgPath',
...@@ -95,6 +105,7 @@ export default { ...@@ -95,6 +105,7 @@ export default {
: ''; : '';
return { return {
isPolicyPreviewHumanVisible: true,
yamlEditorValue, yamlEditorValue,
yamlEditorError: policy.error ? true : null, yamlEditorError: policy.error ? true : null,
policy, policy,
...@@ -107,9 +118,6 @@ export default { ...@@ -107,9 +118,6 @@ export default {
humanizedPolicy() { humanizedPolicy() {
return this.policy.error ? null : humanizeNetworkPolicy(this.policy); return this.policy.error ? null : humanizeNetworkPolicy(this.policy);
}, },
initialTab() {
return this.hasParsingError ? 1 : 0;
},
policyAlert() { policyAlert() {
return Boolean(this.policy.annotations); return Boolean(this.policy.annotations);
}, },
...@@ -219,7 +227,12 @@ export default { ...@@ -219,7 +227,12 @@ export default {
@update-yaml="updateYaml" @update-yaml="updateYaml"
> >
<template #rule-editor> <template #rule-editor>
<gl-alert v-if="hasParsingError" data-testid="parsing-alert" :dismissible="false"> <gl-alert
v-if="hasParsingError"
data-testid="parsing-alert"
class="gl-mb-5"
:dismissible="false"
>
{{ $options.i18n.PARSING_ERROR_MESSAGE }} {{ $options.i18n.PARSING_ERROR_MESSAGE }}
</gl-alert> </gl-alert>
...@@ -290,17 +303,31 @@ export default { ...@@ -290,17 +303,31 @@ export default {
</dim-disable-container> </dim-disable-container>
</template> </template>
<template #rule-editor-preview> <template #rule-editor-preview>
<dim-disable-container data-testid="policy-preview-container" :disabled="hasParsingError"> <h5>{{ $options.i18n.yamlPreview }}</h5>
<template #title> <pre
<h5>{{ $options.i18n.policyPreview }}</h5> data-testid="yaml-preview"
</template> class="gl-bg-white gl-border-none gl-p-0"
:class="{ 'gl-opacity-5': hasParsingError }"
<template #disabled> >{{ policyYaml || yamlEditorValue }}</pre
<policy-preview :initial-tab="initialTab" :policy-yaml="yamlEditorValue" /> >
</template> </template>
<template v-if="!hasParsingError" #bottom>
<policy-preview :policy-yaml="policyYaml" :policy-description="humanizedPolicy" /> <div class="gl-my-6">
</dim-disable-container> <gl-button
v-collapse-toggle="$options.policyPreviewHumanCollapseId"
category="tertiary"
class="gl-font-weight-bold gl-bg-transparent! gl-px-0!"
>
{{ $options.i18n.policyPreview }}
<gl-icon :name="isPolicyPreviewHumanVisible ? 'angle-up' : 'angle-down'" :size="12" />
</gl-button>
<gl-collapse
:id="$options.policyPreviewHumanCollapseId"
v-model="isPolicyPreviewHumanVisible"
>
<policy-preview-human class="gl-md-w-70p" :policy-description="humanizedPolicy" />
</gl-collapse>
</div>
</template> </template>
</policy-editor-layout> </policy-editor-layout>
<gl-empty-state <gl-empty-state
......
...@@ -160,6 +160,7 @@ export default { ...@@ -160,6 +160,7 @@ export default {
</section> </section>
</div> </div>
</div> </div>
<slot name="bottom"></slot>
<span <span
v-gl-tooltip.hover.focus="{ disabled: disableTooltip }" v-gl-tooltip.hover.focus="{ disabled: disableTooltip }"
class="gl-pt-2" class="gl-pt-2"
......
<script> <script>
import { GlAlert, GlTabs, GlTab, GlSafeHtmlDirective } from '@gitlab/ui'; import { GlTabs, GlTab } from '@gitlab/ui';
import { PARSING_ERROR_MESSAGE } from './constants'; import { PARSING_ERROR_MESSAGE } from './constants';
import PolicyPreviewHuman from './policy_preview_human.vue';
export default { export default {
i18n: { i18n: {
PARSING_ERROR_MESSAGE, PARSING_ERROR_MESSAGE,
}, },
components: { components: {
GlAlert,
GlTabs, GlTabs,
GlTab, GlTab,
}, PolicyPreviewHuman,
directives: {
safeHtml: GlSafeHtmlDirective,
}, },
props: { props: {
policyYaml: { policyYaml: {
...@@ -33,23 +31,20 @@ export default { ...@@ -33,23 +31,20 @@ export default {
data() { data() {
return { selectedTab: this.initialTab }; return { selectedTab: this.initialTab };
}, },
safeHtmlConfig: { ALLOWED_TAGS: ['strong', 'br'] },
}; };
</script> </script>
<template> <template>
<gl-tabs v-model="selectedTab" content-class="gl-pt-0"> <gl-tabs v-model="selectedTab" content-class="gl-pt-0">
<gl-tab :title="s__('NetworkPolicies|Rule')"> <gl-tab :title="s__('NetworkPolicies|Rule')">
<div <policy-preview-human
v-if="policyDescription" :class="{
v-safe-html:[$options.safeHtmlConfig]="policyDescription" 'gl-border-t-none! gl-rounded-top-left-none gl-rounded-top-right-none': Boolean(
class="gl-bg-white gl-rounded-top-left-none gl-rounded-top-right-none gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-py-3 gl-px-4 gl-border-1 gl-border-solid gl-border-gray-100 gl-border-t-none!" policyDescription,
></div> ),
<div v-else> }"
<gl-alert variant="info" :dismissible="false"> :policy-description="policyDescription"
{{ $options.i18n.PARSING_ERROR_MESSAGE }} />
</gl-alert>
</div>
</gl-tab> </gl-tab>
<gl-tab :title="s__('NetworkPolicies|.yaml')"> <gl-tab :title="s__('NetworkPolicies|.yaml')">
<pre class="gl-bg-white gl-rounded-top-left-none gl-rounded-top-right-none gl-border-t-none" <pre class="gl-bg-white gl-rounded-top-left-none gl-rounded-top-right-none gl-border-t-none"
......
<script>
import { GlAlert, GlSafeHtmlDirective } from '@gitlab/ui';
import { PARSING_ERROR_MESSAGE } from './constants';
export default {
i18n: {
PARSING_ERROR_MESSAGE,
},
components: {
GlAlert,
},
directives: {
safeHtml: GlSafeHtmlDirective,
},
props: {
policyDescription: {
type: String,
required: false,
default: '',
},
},
safeHtmlConfig: { ALLOWED_TAGS: ['strong', 'br'] },
};
</script>
<template>
<div
v-if="policyDescription"
v-safe-html:[$options.safeHtmlConfig]="policyDescription"
class="gl-bg-white gl-rounded-base gl-py-3 gl-px-4 gl-border-1 gl-border-solid gl-border-gray-100"
></div>
<div v-else>
<gl-alert variant="info" :dismissible="false">
{{ $options.i18n.PARSING_ERROR_MESSAGE }}
</gl-alert>
</div>
</template>
...@@ -11,15 +11,10 @@ exports[`PolicyPreview component with policy description renders policy preview ...@@ -11,15 +11,10 @@ exports[`PolicyPreview component with policy description renders policy preview
title="Rule" title="Rule"
titlelinkclass="" titlelinkclass=""
> >
<div <policy-preview-human-stub
class="gl-bg-white gl-rounded-top-left-none gl-rounded-top-right-none gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-py-3 gl-px-4 gl-border-1 gl-border-solid gl-border-gray-100 gl-border-t-none!" class="gl-border-t-none! gl-rounded-top-left-none gl-rounded-top-right-none"
> policydescription="<strong>bar</strong><br><div>test</div><script></script>"
<strong> />
bar
</strong>
<br />
test
</div>
</gl-tab-stub> </gl-tab-stub>
<gl-tab-stub <gl-tab-stub
......
...@@ -13,9 +13,11 @@ import NetworkPolicyEditor from 'ee/threat_monitoring/components/policy_editor/n ...@@ -13,9 +13,11 @@ import NetworkPolicyEditor from 'ee/threat_monitoring/components/policy_editor/n
import PolicyRuleBuilder from 'ee/threat_monitoring/components/policy_editor/network_policy/policy_rule_builder.vue'; import PolicyRuleBuilder from 'ee/threat_monitoring/components/policy_editor/network_policy/policy_rule_builder.vue';
import PolicyAlertPicker from 'ee/threat_monitoring/components/policy_editor/policy_alert_picker.vue'; import PolicyAlertPicker from 'ee/threat_monitoring/components/policy_editor/policy_alert_picker.vue';
import PolicyEditorLayout from 'ee/threat_monitoring/components/policy_editor/policy_editor_layout.vue'; import PolicyEditorLayout from 'ee/threat_monitoring/components/policy_editor/policy_editor_layout.vue';
import PolicyPreview from 'ee/threat_monitoring/components/policy_editor/policy_preview.vue'; import PolicyPreviewHuman from 'ee/threat_monitoring/components/policy_editor/policy_preview_human.vue';
import createStore from 'ee/threat_monitoring/store'; import createStore from 'ee/threat_monitoring/store';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { stubTransition } from 'helpers/stub_transition';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { mockExistingL3Policy, mockExistingL7Policy } from '../../../mocks/mock_data'; import { mockExistingL3Policy, mockExistingL7Policy } from '../../../mocks/mock_data';
...@@ -29,7 +31,12 @@ describe('NetworkPolicyEditor component', () => { ...@@ -29,7 +31,12 @@ describe('NetworkPolicyEditor component', () => {
threatMonitoring: { environments: [{ id: 1 }], currentEnvironmentId: 1, hasEnvironment: true }, threatMonitoring: { environments: [{ id: 1 }], currentEnvironmentId: 1, hasEnvironment: true },
}; };
const factory = ({ propsData, provide = {}, updatedStore = defaultStore } = {}) => { const factory = ({
propsData,
provide = {},
updatedStore = defaultStore,
mountFn = shallowMountExtended,
} = {}) => {
store = createStore(); store = createStore();
store.replaceState({ store.replaceState({
...@@ -46,7 +53,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -46,7 +53,7 @@ describe('NetworkPolicyEditor component', () => {
jest.spyOn(store, 'dispatch').mockImplementation(() => Promise.resolve()); jest.spyOn(store, 'dispatch').mockImplementation(() => Promise.resolve());
wrapper = shallowMountExtended(NetworkPolicyEditor, { wrapper = mountFn(NetworkPolicyEditor, {
propsData: { propsData: {
...propsData, ...propsData,
}, },
...@@ -58,12 +65,13 @@ describe('NetworkPolicyEditor component', () => { ...@@ -58,12 +65,13 @@ describe('NetworkPolicyEditor component', () => {
...provide, ...provide,
}, },
store, store,
stubs: { DimDisableContainer, PolicyYamlEditor: true }, stubs: { DimDisableContainer, PolicyYamlEditor: true, transition: stubTransition() },
}); });
}; };
const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findPreview = () => wrapper.findComponent(PolicyPreview); const findYamlPreview = () => wrapper.findByTestId('yaml-preview');
const findHumanizedPreview = () => wrapper.findComponent(PolicyPreviewHuman);
const findAddRuleButton = () => wrapper.findByTestId('add-rule'); const findAddRuleButton = () => wrapper.findByTestId('add-rule');
const findYAMLParsingAlert = () => wrapper.findByTestId('parsing-alert'); const findYAMLParsingAlert = () => wrapper.findByTestId('parsing-alert');
const findPolicyAlertPicker = () => wrapper.findComponent(PolicyAlertPicker); const findPolicyAlertPicker = () => wrapper.findComponent(PolicyAlertPicker);
...@@ -72,6 +80,10 @@ describe('NetworkPolicyEditor component', () => { ...@@ -72,6 +80,10 @@ describe('NetworkPolicyEditor component', () => {
const findPolicyName = () => wrapper.find("[id='policyName']"); const findPolicyName = () => wrapper.find("[id='policyName']");
const findPolicyRuleBuilder = () => wrapper.findComponent(PolicyRuleBuilder); const findPolicyRuleBuilder = () => wrapper.findComponent(PolicyRuleBuilder);
const findPolicyEditorLayout = () => wrapper.findComponent(PolicyEditorLayout); const findPolicyEditorLayout = () => wrapper.findComponent(PolicyEditorLayout);
const findCollapseToggle = () =>
wrapper.findByRole('button', {
name: NetworkPolicyEditor.i18n.policyPreview,
});
const modifyPolicyAlert = async ({ isAlertEnabled }) => { const modifyPolicyAlert = async ({ isAlertEnabled }) => {
const policyAlertPicker = findPolicyAlertPicker(); const policyAlertPicker = findPolicyAlertPicker();
...@@ -80,21 +92,19 @@ describe('NetworkPolicyEditor component', () => { ...@@ -80,21 +92,19 @@ describe('NetworkPolicyEditor component', () => {
await findPolicyEditorLayout().vm.$emit('save-policy'); await findPolicyEditorLayout().vm.$emit('save-policy');
}; };
beforeEach(() => {
factory();
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders toggle with label', () => { it('renders toggle with label', () => {
factory();
const policyEnableToggle = findPolicyEnableContainer().findComponent(GlToggle); const policyEnableToggle = findPolicyEnableContainer().findComponent(GlToggle);
expect(policyEnableToggle.exists()).toBe(true); expect(policyEnableToggle.exists()).toBe(true);
expect(policyEnableToggle.props('label')).toBe(NetworkPolicyEditor.i18n.toggleLabel); expect(policyEnableToggle.props('label')).toBe(NetworkPolicyEditor.i18n.toggleLabel);
}); });
it('disables the tooltip and enables the save button', () => { it('disables the tooltip and enables the save button', () => {
factory();
expect(findPolicyEditorLayout().props()).toMatchObject({ expect(findPolicyEditorLayout().props()).toMatchObject({
disableTooltip: true, disableTooltip: true,
disableUpdate: false, disableUpdate: false,
...@@ -102,6 +112,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -102,6 +112,7 @@ describe('NetworkPolicyEditor component', () => {
}); });
it('renders a default rule with label', () => { it('renders a default rule with label', () => {
factory();
expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(1); expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(1);
expect(findPolicyRuleBuilder().exists()).toBe(true); expect(findPolicyRuleBuilder().exists()).toBe(true);
expect(findPolicyRuleBuilder().attributes()).toMatchObject({ expect(findPolicyRuleBuilder().attributes()).toMatchObject({
...@@ -115,14 +126,16 @@ describe('NetworkPolicyEditor component', () => { ...@@ -115,14 +126,16 @@ describe('NetworkPolicyEditor component', () => {
${'policy alert picker'} | ${'does display'} | ${findPolicyAlertPicker} | ${true} ${'policy alert picker'} | ${'does display'} | ${findPolicyAlertPicker} | ${true}
${'policy name input'} | ${'does display'} | ${findPolicyName} | ${true} ${'policy name input'} | ${'does display'} | ${findPolicyName} | ${true}
${'add rule button'} | ${'does display'} | ${findAddRuleButton} | ${true} ${'add rule button'} | ${'does display'} | ${findAddRuleButton} | ${true}
${'policy preview'} | ${'does display'} | ${findPreview} | ${true} ${'yaml policy preview'} | ${'does display'} | ${findYamlPreview} | ${true}
${'parsing error alert'} | ${'does not display'} | ${findYAMLParsingAlert} | ${false} ${'parsing error alert'} | ${'does not display'} | ${findYAMLParsingAlert} | ${false}
${'no environment empty state'} | ${'does not display'} | ${findEmptyState} | ${false} ${'no environment empty state'} | ${'does not display'} | ${findEmptyState} | ${false}
`('$status the $component', async ({ findComponent, state }) => { `('$status the $component', async ({ findComponent, state }) => {
factory();
expect(findComponent().exists()).toBe(state); expect(findComponent().exists()).toBe(state);
}); });
it('updates policy on yaml editor value change', async () => { it('updates policy on yaml editor value change', async () => {
factory();
findPolicyEditorLayout().vm.$emit('update-yaml', mockExistingL3Policy.manifest); findPolicyEditorLayout().vm.$emit('update-yaml', mockExistingL3Policy.manifest);
expect(wrapper.vm.policy).toMatchObject({ expect(wrapper.vm.policy).toMatchObject({
...@@ -142,18 +155,37 @@ describe('NetworkPolicyEditor component', () => { ...@@ -142,18 +155,37 @@ describe('NetworkPolicyEditor component', () => {
}); });
it('given there is a name change, updates policy yaml preview', async () => { it('given there is a name change, updates policy yaml preview', async () => {
const initialValue = findPreview().props('policyYaml'); factory();
const initialValue = findYamlPreview().text();
await findPolicyName().vm.$emit('input', 'new'); await findPolicyName().vm.$emit('input', 'new');
expect(findPreview().props('policyYaml')).not.toEqual(initialValue); expect(findYamlPreview().text()).not.toEqual(initialValue);
}); });
it('given there is a rule change, updates policy description preview', async () => { it('given there is a rule change, updates policy description preview', async () => {
const initialValue = findPreview().props('policyDescription'); factory();
const initialValue = findHumanizedPreview().props('policyDescription');
await findAddRuleButton().vm.$emit('click'); await findAddRuleButton().vm.$emit('click');
expect(findPreview().props('policyDescription')).not.toEqual(initialValue); expect(findHumanizedPreview().props('policyDescription')).not.toEqual(initialValue);
});
it('toggles the visibility for the humanized policy preview', async () => {
factory({ mountFn: mountExtended });
// Wait for `requestAnimationFrame` in Bootstrap Vue toggle directive
// https://github.com/bootstrap-vue/bootstrap-vue/blob/f86c32a7d8a3c0403c9a9421850ce3c97f0ad638/src/directives/toggle/toggle.js#L219
await waitForPromises();
expect(findHumanizedPreview().isVisible()).toBe(true);
expect(findCollapseToggle().attributes('aria-expanded')).toBe('true');
await findCollapseToggle().trigger('click');
expect(findHumanizedPreview().isVisible()).toBe(false);
expect(findCollapseToggle().attributes('aria-expanded')).toBe('false');
}); });
it('adds a new rule', async () => { it('adds a new rule', async () => {
factory();
expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(1); expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(1);
const button = findAddRuleButton(); const button = findAddRuleButton();
await button.vm.$emit('click'); await button.vm.$emit('click');
...@@ -174,6 +206,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -174,6 +206,7 @@ describe('NetworkPolicyEditor component', () => {
}); });
it('removes a new rule', async () => { it('removes a new rule', async () => {
factory();
await findAddRuleButton().vm.$emit('click'); await findAddRuleButton().vm.$emit('click');
expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(2); expect(wrapper.findAllComponents(PolicyRuleBuilder)).toHaveLength(2);
...@@ -182,6 +215,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -182,6 +215,7 @@ describe('NetworkPolicyEditor component', () => {
}); });
it('updates yaml editor value on switch to yaml editor', async () => { it('updates yaml editor value on switch to yaml editor', async () => {
factory();
const policyEditorLayout = findPolicyEditorLayout(); const policyEditorLayout = findPolicyEditorLayout();
findPolicyName().vm.$emit('input', 'test-policy'); findPolicyName().vm.$emit('input', 'test-policy');
await policyEditorLayout.vm.$emit('update-editor-mode', EDITOR_MODE_YAML); await policyEditorLayout.vm.$emit('update-editor-mode', EDITOR_MODE_YAML);
...@@ -207,6 +241,10 @@ describe('NetworkPolicyEditor component', () => { ...@@ -207,6 +241,10 @@ describe('NetworkPolicyEditor component', () => {
expect(findPolicyEnableContainer().attributes().disabled).toBe('true'); expect(findPolicyEnableContainer().attributes().disabled).toBe('true');
}); });
it('does not display the humanized policy preview', () => {
expect(findHumanizedPreview().exists()).toBe(false);
});
it('renders parsing error alert', () => { it('renders parsing error alert', () => {
expect(findYAMLParsingAlert().exists()).toBe(true); expect(findYAMLParsingAlert().exists()).toBe(true);
}); });
...@@ -219,12 +257,10 @@ describe('NetworkPolicyEditor component', () => { ...@@ -219,12 +257,10 @@ describe('NetworkPolicyEditor component', () => {
expect(wrapper.findByTestId('policy-action-container').props().disabled).toBe(true); expect(wrapper.findByTestId('policy-action-container').props().disabled).toBe(true);
}); });
it('disables policy preview and sets initial tab to yaml', () => { it('displays the manifest text and decreases the opacity to show it is disabled', () => {
expect(wrapper.findByTestId('policy-preview-container').props().disabled).toBe(true); const preview = findYamlPreview();
expect(findPreview().props()).toMatchObject({ expect(preview.attributes('class')).toContain('gl-opacity-5');
initialTab: 1, expect(preview.text()).toBe(mockExistingL7Policy.manifest);
policyYaml: mockExistingL7Policy.manifest,
});
}); });
it('does not update yaml editor value on switch to yaml editor', async () => { it('does not update yaml editor value on switch to yaml editor', async () => {
...@@ -257,6 +293,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -257,6 +293,7 @@ describe('NetworkPolicyEditor component', () => {
}); });
it('creates policy and redirects to a threat monitoring path', async () => { it('creates policy and redirects to a threat monitoring path', async () => {
factory();
await findPolicyEditorLayout().vm.$emit('save-policy'); await findPolicyEditorLayout().vm.$emit('save-policy');
expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/createPolicy', { expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/createPolicy', {
environmentId: 1, environmentId: 1,
...@@ -335,6 +372,10 @@ describe('NetworkPolicyEditor component', () => { ...@@ -335,6 +372,10 @@ describe('NetworkPolicyEditor component', () => {
}); });
describe('add alert picker', () => { describe('add alert picker', () => {
beforeEach(() => {
factory();
});
it('adds a policy annotation on alert addition', async () => { it('adds a policy annotation on alert addition', async () => {
await modifyPolicyAlert({ isAlertEnabled: true }); await modifyPolicyAlert({ isAlertEnabled: true });
expect(store.dispatch).toHaveBeenLastCalledWith('networkPolicies/createPolicy', { expect(store.dispatch).toHaveBeenLastCalledWith('networkPolicies/createPolicy', {
......
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import PolicyPreviewHuman from 'ee/threat_monitoring/components/policy_editor/policy_preview_human.vue';
describe('PolicyPreviewHuman component', () => {
let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert);
const factory = ({ propsData } = {}) => {
wrapper = shallowMount(PolicyPreviewHuman, {
propsData: {
...propsData,
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('when policy description is not defined', () => {
beforeEach(() => {
factory();
});
it('renders an alert when policyDescription is not defined', () => {
expect(findAlert().exists()).toBe(true);
});
});
describe('when policy description is defined', () => {
const policyDescription = '<strong>bar</strong><br><div>test</div><script></script>';
const policyDescriptionSafe = '<strong>bar</strong><br>test';
beforeEach(() => {
factory({
propsData: {
policyDescription,
},
});
});
it('renders the policyDescription when it is defined', () => {
expect(wrapper.html()).toContain(policyDescriptionSafe);
});
it('does not render the alert component', () => {
expect(findAlert().exists()).toBe(false);
});
});
});
import { GlAlert, GlTabs } from '@gitlab/ui'; import { GlTabs } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import PolicyPreviewHuman from 'ee/threat_monitoring/components/policy_editor/policy_preview_human.vue';
import PolicyPreview from 'ee/threat_monitoring/components/policy_editor/policy_preview.vue'; import PolicyPreview from 'ee/threat_monitoring/components/policy_editor/policy_preview.vue';
describe('PolicyPreview component', () => { describe('PolicyPreview component', () => {
let wrapper; let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert);
const findTabs = () => wrapper.findComponent(GlTabs); const findTabs = () => wrapper.findComponent(GlTabs);
const findPolicyPreviewHuman = () => wrapper.findComponent(PolicyPreviewHuman);
const factory = ({ propsData } = {}) => { const factory = ({ propsData } = {}) => {
wrapper = shallowMount(PolicyPreview, { wrapper = shallowMount(PolicyPreview, {
...@@ -21,11 +22,13 @@ describe('PolicyPreview component', () => { ...@@ -21,11 +22,13 @@ describe('PolicyPreview component', () => {
}); });
describe('with policy description', () => { describe('with policy description', () => {
const policyDescription = '<strong>bar</strong><br><div>test</div><script></script>';
beforeEach(() => { beforeEach(() => {
factory({ factory({
propsData: { propsData: {
policyYaml: 'foo', policyYaml: 'foo',
policyDescription: '<strong>bar</strong><br><div>test</div><script></script>', policyDescription,
}, },
}); });
}); });
...@@ -34,12 +37,12 @@ describe('PolicyPreview component', () => { ...@@ -34,12 +37,12 @@ describe('PolicyPreview component', () => {
expect(findTabs().element).toMatchSnapshot(); expect(findTabs().element).toMatchSnapshot();
}); });
it('renders the first tab', () => { it('renders the policy preview human', () => {
expect(findTabs().attributes().value).toEqual('0'); expect(findPolicyPreviewHuman().props('policyDescription')).toBe(policyDescription);
}); });
it('does not render the unsupported attributes alert', () => { it('renders the first tab', () => {
expect(findAlert().exists()).toBe(false); expect(findTabs().attributes().value).toEqual('0');
}); });
describe('initial tab', () => { describe('initial tab', () => {
...@@ -64,9 +67,5 @@ describe('PolicyPreview component', () => { ...@@ -64,9 +67,5 @@ describe('PolicyPreview component', () => {
}, },
}); });
}); });
it('does render the unsupported attributes alert', () => {
expect(findAlert().exists()).toBe(true);
});
}); });
}); });
...@@ -31064,6 +31064,9 @@ msgstr "" ...@@ -31064,6 +31064,9 @@ msgstr ""
msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}" msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
msgstr "" msgstr ""
msgid "SecurityOrchestration|.yaml preview"
msgstr ""
msgid "SecurityOrchestration|Action" msgid "SecurityOrchestration|Action"
msgstr "" msgstr ""
......
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