diff --git a/app/assets/javascripts/vue_shared/components/action_card.stories.js b/app/assets/javascripts/vue_shared/components/action_card.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..2e3aab27ac412f2d97cf5e8b35c240ef582b887a --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/action_card.stories.js @@ -0,0 +1,30 @@ +import ActionCard, { VARIANTS } from './action_card.vue'; + +export default { + component: ActionCard, + title: 'vue_shared/action_card', + argTypes: { + variant: { + control: 'select', + options: Object.values(VARIANTS), + }, + }, +}; + +const Template = (args, { argTypes }) => ({ + components: { ActionCard }, + props: Object.keys(argTypes), + template: ` + + `, +}); + +export const Default = Template.bind({}); +Default.args = { + title: 'Create a project', + description: + 'Projects are where you store your code, access issues, wiki, and other features of GitLab.', + icon: 'project', + variant: VARIANTS.default, + href: 'gitlab.com', +}; diff --git a/app/assets/javascripts/vue_shared/components/action_card.vue b/app/assets/javascripts/vue_shared/components/action_card.vue new file mode 100644 index 0000000000000000000000000000000000000000..3138266132af955de927b1cf5d996e6b020fbd6e --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/action_card.vue @@ -0,0 +1,62 @@ + + + diff --git a/app/assets/stylesheets/components/action_card_component.scss b/app/assets/stylesheets/components/action_card_component.scss index 1db8f35b670bcf1530da9e679d99c70ad67fc621..9c6dd2422fc1f74c237c0b73b5725683193032be 100644 --- a/app/assets/stylesheets/components/action_card_component.scss +++ b/app/assets/stylesheets/components/action_card_component.scss @@ -64,7 +64,7 @@ text-wrap: balance; } - &-controls { + &-controls:not(:empty) { margin-top: $gl-spacing-scale-4; } } diff --git a/spec/components/previews/onboarding/action_card_component_preview.rb b/spec/components/previews/onboarding/action_card_component_preview.rb index 798a56caf10db5dbf270e1f2b40e51ca91d78e54..844f5a73d403641c9491a8dece7f4868fbb6a883 100644 --- a/spec/components/previews/onboarding/action_card_component_preview.rb +++ b/spec/components/previews/onboarding/action_card_component_preview.rb @@ -17,8 +17,8 @@ def default( description: "Groups are the best way to manage projects and members", title: "Create a group") render Onboarding::ActionCardComponent.new( - title, - description, + title: title, + description: description, icon: icon, href: href, variant: variant diff --git a/spec/frontend/vue_shared/components/action_card_spec.js b/spec/frontend/vue_shared/components/action_card_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..4382c4d31c8f298772fd8d08e09c0268d85cdb64 --- /dev/null +++ b/spec/frontend/vue_shared/components/action_card_spec.js @@ -0,0 +1,93 @@ +import { GlLink } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import ActionCard from '~/vue_shared/components/action_card.vue'; + +describe('Action card', () => { + let wrapper; + + const createComponent = ({ propsData = {} } = {}) => { + wrapper = shallowMountExtended(ActionCard, { + propsData: { + title: 'Create a project', + description: + 'Projects are where you store your code, access issues, wiki, and other features of GitLab.', + icon: 'project', + ...propsData, + }, + }); + }; + + const findTitle = () => wrapper.findByTestId('action-card-title'); + const findTitleLink = () => wrapper.findComponent(GlLink); + const findDescription = () => wrapper.findByTestId('action-card-description'); + const findCardIcon = () => wrapper.findByTestId('action-card-icon'); + const findArrowIcon = () => wrapper.findByTestId('action-card-arrow-icon'); + + const baseCardClass = 'action-card'; + + describe('default', () => { + beforeEach(() => { + createComponent(); + }); + + it('applies default variant styles', () => { + expect(wrapper.classes()).toContain(baseCardClass, 'action-card-default'); + }); + + it('renders title', () => { + expect(findTitle().text()).toBe('Create a project'); + }); + + it('renders description', () => { + expect(findDescription().text()).toBe( + 'Projects are where you store your code, access issues, wiki, and other features of GitLab.', + ); + }); + + it('renders card icon', () => { + expect(findCardIcon().props('name')).toBe('project'); + }); + + it('does not render link', () => { + expect(findTitleLink().exists()).toBe(false); + }); + }); + + describe('with link', () => { + beforeEach(() => { + createComponent({ propsData: { href: 'gitlab.com' } }); + }); + + it('renders link', () => { + expect(findTitleLink().exists()).toBe(true); + expect(findTitleLink().text()).toBe('Create a project'); + expect(findTitleLink().attributes('href')).toBe('gitlab.com'); + }); + + it('renders card icon', () => { + expect(findCardIcon().props('name')).toBe('project'); + }); + + it('renders arrow icon', () => { + expect(findArrowIcon().exists()).toBe(true); + }); + }); + + describe.each` + variant | expectedVariantClass | expectedCardIcon + ${'success'} | ${'action-card-success'} | ${'check'} + ${'promo'} | ${'action-card-promo'} | ${'project'} + `('when variant is $variant', ({ variant, expectedVariantClass, expectedCardIcon }) => { + beforeEach(() => { + createComponent({ propsData: { variant } }); + }); + + it('applies correct variant styles', () => { + expect(wrapper.classes()).toContain(baseCardClass, expectedVariantClass); + }); + + it('renders correct card icon', () => { + expect(findCardIcon().props('name')).toBe(expectedCardIcon); + }); + }); +});