Commit 14690b18 authored by Mark Florian's avatar Mark Florian

Add ExpandableSection component

Addresses https://gitlab.com/gitlab-org/gitlab/-/issues/233521.
parent a0f63899
<script>
import { GlButton, GlCollapse, GlCollapseToggleDirective } from '@gitlab/ui';
import { uniqueId } from 'lodash';
import { __ } from '~/locale';
export default {
components: {
GlButton,
GlCollapse,
},
directives: {
CollapseToggle: GlCollapseToggleDirective,
},
props: {
headingTag: {
type: String,
required: false,
default: 'h3',
},
},
data: () => ({
collapseId: uniqueId('expandable-section-'),
visible: false,
}),
computed: {
toggleText() {
return this.visible ? __('Collapse') : __('Expand');
},
},
};
</script>
<template>
<section
class="gl-py-6 gl-border-t-1 gl-border-b-1 gl-border-gray-100 gl-border-t-solid gl-border-b-solid"
>
<header class="gl-display-flex">
<div class="gl-flex-grow-1">
<component :is="headingTag" class="gl-font-size-h2 gl-mt-0" data-testid="heading">
<slot name="heading"></slot>
</component>
<p class="gl-mb-0" data-testid="subheading">
<slot name="subheading"></slot>
</p>
</div>
<gl-button
v-collapse-toggle="collapseId"
class="gl-flex-shrink-0 gl-align-self-start gl-ml-3"
>{{ toggleText }}</gl-button
>
</header>
<gl-collapse :id="collapseId" v-model="visible" data-testid="content">
<div class="gl-mt-6"><slot></slot></div>
</gl-collapse>
</section>
</template>
import { mount, shallowMount } from '@vue/test-utils';
import ExpandableSection from 'ee/security_configuration/sast/components/expandable_section.vue';
describe('ExpandableSection component', () => {
let wrapper;
const createComponent = (options, mountFn = shallowMount) => {
wrapper = mountFn(ExpandableSection, options);
};
const findButton = () => wrapper.find('button');
const findHeading = () => wrapper.find('[data-testid="heading"]');
const findSubHeading = () => wrapper.find('[data-testid="subheading"]');
const findContent = () => wrapper.find('[data-testid="content"]');
afterEach(() => {
wrapper.destroy();
});
describe('headingTag', () => {
it('defaults to h3', () => {
createComponent();
expect(findHeading().element.tagName).toBe('H3');
});
it('uses the given the heading tag name', () => {
const headingTag = 'h6';
createComponent({
propsData: { headingTag },
});
expect(findHeading().element.tagName).toBe(headingTag.toUpperCase());
});
});
describe('heading slot', () => {
beforeEach(() => {
createComponent({
slots: { heading: 'some heading' },
});
});
it('renders the given heading content', () => {
expect(findHeading().html()).toContain('some heading');
});
});
describe('subheading slot', () => {
beforeEach(() => {
createComponent({
slots: { subheading: 'some subheading' },
});
});
it('renders the given subheading content', () => {
expect(findSubHeading().html()).toContain('some subheading');
});
});
describe('default slot', () => {
beforeEach(() => {
createComponent({
slots: { default: 'some content' },
});
});
it('renders the given content', () => {
expect(findContent().html()).toContain('some content');
});
});
describe('expand/collapse behavior', () => {
beforeEach(() => {
createComponent({}, mount);
});
it('hides the content by default', () => {
expect(findContent().isVisible()).toBe(false);
});
it('shows an expand button', () => {
expect(findButton().text()).toBe('Expand');
});
describe('clicking the expand button', () => {
beforeEach(() => {
const button = findButton();
button.trigger('click');
return wrapper.vm.$nextTick();
});
it('shows the content', () => {
expect(findContent().isVisible()).toBe(true);
});
it('shows a collapse button', () => {
expect(findButton().text()).toBe('Collapse');
});
});
});
});
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