From 2245f6571daa1ff4270919f7b24b8c7c848081cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Aguilar?= Date: Wed, 8 May 2024 11:44:38 +0200 Subject: [PATCH] [CHUX-457] Create letter-icon component (#1945) * [CHUX-457] add component and story * [CHUX-457] add unit tests and snapshot * [CHUX-457] add image snapshots * [CHUX-457] change text color on hover * [CHUX-457] design feedback * 2.8.4 * [CHUX-457] revert version bump * [CHUX-457] use button element if icon is clickable * [CHUX-457] always display uppercase letter * [CHUX-457] replace svg * [CHUX-457] coverage * [CHUX-457] remove leftover styles * [CHUX-457] computed refactor * [CHUX-457] size enum * [CHUX-457] hide icon if text prop is empty --- .../__snapshots__/ec-letter-icon.spec.ts.snap | 15 ++++ .../ec-letter-icon/ec-letter-icon.spec.ts | 73 ++++++++++++++++++ .../ec-letter-icon/ec-letter-icon.story.ts | 40 ++++++++++ .../ec-letter-icon/ec-letter-icon.vue | 66 ++++++++++++++++ src/components/ec-letter-icon/index.ts | 1 + src/components/ec-letter-icon/types.ts | 10 +++ .../letter-icon--basic__chrome.snap.png | Bin 0 -> 4868 bytes .../letter-icon--basic__firefox.snap.png | Bin 0 -> 5463 bytes 8 files changed, 205 insertions(+) create mode 100644 src/components/ec-letter-icon/__snapshots__/ec-letter-icon.spec.ts.snap create mode 100644 src/components/ec-letter-icon/ec-letter-icon.spec.ts create mode 100644 src/components/ec-letter-icon/ec-letter-icon.story.ts create mode 100644 src/components/ec-letter-icon/ec-letter-icon.vue create mode 100644 src/components/ec-letter-icon/index.ts create mode 100644 src/components/ec-letter-icon/types.ts create mode 100644 tests/integration/snapshots/visual-regression.spec.js/letter-icon--basic__chrome.snap.png create mode 100644 tests/integration/snapshots/visual-regression.spec.js/letter-icon--basic__firefox.snap.png diff --git a/src/components/ec-letter-icon/__snapshots__/ec-letter-icon.spec.ts.snap b/src/components/ec-letter-icon/__snapshots__/ec-letter-icon.spec.ts.snap new file mode 100644 index 000000000..4cdd89cff --- /dev/null +++ b/src/components/ec-letter-icon/__snapshots__/ec-letter-icon.spec.ts.snap @@ -0,0 +1,15 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`EcLetterIcon > should render as expected 1`] = ` +
+ + T + +
+`; diff --git a/src/components/ec-letter-icon/ec-letter-icon.spec.ts b/src/components/ec-letter-icon/ec-letter-icon.spec.ts new file mode 100644 index 000000000..06f8a21ae --- /dev/null +++ b/src/components/ec-letter-icon/ec-letter-icon.spec.ts @@ -0,0 +1,73 @@ +import { type ComponentMountingOptions, mount } from '@vue/test-utils'; + +import EcLetterIcon from './ec-letter-icon.vue'; +import { type LetterIconProps, LetterIconSize } from './types'; + +describe('EcLetterIcon', () => { + function mountLetterIcon(props: LetterIconProps, mountOpts?: ComponentMountingOptions) { + return mount( + EcLetterIcon, + { + props: { + ...props, + }, + ...mountOpts, + }, + ); + } + + it('should render as expected', () => { + const wrapper = mountLetterIcon({ + text: 'Test', + }); + expect(wrapper.element).toMatchSnapshot(); + }); + + it('should render the first letter of the text we passed through prop', () => { + const wrapper = mountLetterIcon({ + text: 'Test', + }); + + const text = wrapper.findByDataTest('ec-letter-icon__text'); + expect(text.text()).toBe('T'); + }); + + it('should render the letter as uppercase if the text begins with a lowercase character', () => { + const wrapper = mountLetterIcon({ + text: 'test', + }); + + const text = wrapper.findByDataTest('ec-letter-icon__text'); + expect(text.text()).toBe('T'); + }); + + it('should not display the icon if text is an empty string', () => { + const wrapper = mountLetterIcon({ + text: '', + }); + + const container = wrapper.findByDataTest('ec-letter-icon'); + expect(container.exists()).toBe(false); + }); + + it('should apply corresponding class if "size" prop is set', () => { + const wrapper = mountLetterIcon({ + text: 'Test', + size: LetterIconSize.MEDIUM, + }); + + const container = wrapper.findByDataTest('ec-letter-icon'); + expect(container.classes()).toContain('ec-letter-icon--md'); + }); + + it('should use button element and add clickable class if "isClickable" prop is set', () => { + const wrapper = mountLetterIcon({ + text: 'Test', + isClickable: true, + }); + + const container = wrapper.findByDataTest('ec-letter-icon'); + expect(container.element.tagName).toContain('BUTTON'); + expect(container.classes()).toContain('ec-letter-icon--clickable'); + }); +}); diff --git a/src/components/ec-letter-icon/ec-letter-icon.story.ts b/src/components/ec-letter-icon/ec-letter-icon.story.ts new file mode 100644 index 000000000..0b6207594 --- /dev/null +++ b/src/components/ec-letter-icon/ec-letter-icon.story.ts @@ -0,0 +1,40 @@ +import type { Meta, StoryFn } from '@storybook/vue3'; + +import EcLetterIcon from './ec-letter-icon.vue'; +import { LetterIconSize } from './types'; + +export default { + title: 'Letter Icon', + component: EcLetterIcon, +} as Meta; + +type EcLetterIconStory = StoryFn; + +const Template: EcLetterIconStory = args => ({ + components: { EcLetterIcon }, + setup() { + return { + args, + }; + }, + template: ` +
+ +
+ `, +}); + +export const basic = Template.bind({}); + +basic.args = { + text: 'Letter Icon', +}; + +basic.argTypes = { + size: { + options: Object.values(LetterIconSize), + control: { type: 'select' }, + }, +}; diff --git a/src/components/ec-letter-icon/ec-letter-icon.vue b/src/components/ec-letter-icon/ec-letter-icon.vue new file mode 100644 index 000000000..d1ac3c301 --- /dev/null +++ b/src/components/ec-letter-icon/ec-letter-icon.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/components/ec-letter-icon/index.ts b/src/components/ec-letter-icon/index.ts new file mode 100644 index 000000000..2349bf301 --- /dev/null +++ b/src/components/ec-letter-icon/index.ts @@ -0,0 +1 @@ +export { default } from './ec-letter-icon.vue'; diff --git a/src/components/ec-letter-icon/types.ts b/src/components/ec-letter-icon/types.ts new file mode 100644 index 000000000..0b6c36ade --- /dev/null +++ b/src/components/ec-letter-icon/types.ts @@ -0,0 +1,10 @@ +export interface LetterIconProps { + text: string, + size?: LetterIconSize, + isClickable?: boolean, +} + +export enum LetterIconSize { + SMALL = 'sm', + MEDIUM = 'md', +} diff --git a/tests/integration/snapshots/visual-regression.spec.js/letter-icon--basic__chrome.snap.png b/tests/integration/snapshots/visual-regression.spec.js/letter-icon--basic__chrome.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..ec71426477bed4c67f7d416113b95ac79644d035 GIT binary patch literal 4868 zcmeHK?@tnO7(X<%)zsD-s)b}W*?M8wYNVp9)ER4?tvSh=P;1J{i6ld$KwN9NvT47R z@)xVMXkn4@0y>u8Z zh+ng54Fo~)oCA4BASi}-jFPR6C74IpC4!*!C?{`UQ61&yi?ZgV*b^~te`KkD-cC>7 zo4l3vB<0z~Vg+>P@}Z*XJEy7dYh%`JY4+H!Fg7k!%5opR?9H#Z%j*))&~Pr{4{G4V z1GZC30jy#VpaVT16m)A8P)NTC(Bs9?fQ_66w4r1Lj4~Z@vom!gW^*~OjOUoB)`=JA zs=_W&&Gm(V+gTtGWU$!>-5=J1gnoGvFv@d9AWbO?Z{5M`A5O=|3}a*1TriWWQXv6} zcm4)_iqS%M-iu`Z>vIBflB%lq4rvO-tR!D@GpE}mZ>8#ZPJvp{?$hgmSBQQe$+dQy zUa9zs)=AH;773v`#Vzzro12!;Q*>!*UgAB}-<_?zrqc1_z{$MOLhF0}Y*^i0-{nTt zrusIN$&DcVQHMlZ`Nolj(1Zyu2>Ycbbf_-uDhE~#flA@{gw$Pg21~UYnoy=}VXiE4 z(6Prb?KhVT(H|%Z1Q3(Z)HXHQ+Qw9>h+pA*+tX?zmTH)CxwZq10ZV)79D!ezOv;Ls zv#-R5AN_-uNdL8s2E#R_FbqclZCejgo|t5_Rv}7!9T0q~XtX`mH)@bR`3-lCMAB-< zKck^Xbar@KOH%gmp*MxrCBx~frM307?Hc84Y0!!X-66DE*{7{1>*LVh~w&m4hCjagdH3pAyAna zAner2;5NI;%3j>fU@(@kOi{DW-UM}Z`yHN1x%V3jm<&j>90}Q&XOblsv6b?mqSB7PI!*?NgehrT%Zj?nCGx{DyDd5pT8FwrC!Wit$W%}%zZL#sW; zE1R;6G7+Qkjeo*`X$N0(5*l-1I_uT=_rcB_`3B(i(pavPD`=IsQe{!AoHwoY1tOl&7-oFJCo(Y&ct`Hx@r0Xm`%GlvjLL2Lp4+ z@e7dF=0`x5(iQ~S`BX@a&!Io$?kJ>4M>M1bxoaRBUIoyHU51CvpFfL4;_10@JwXtp zZ&}We^$Ef<9=D8g7G+}($WkR2#xr5rL2b}=_28XS>x{R4Xhr=+BC!GeByBr2qjylF zvmM>arQLN?Q&1g=bzB!z%H+4lq$c{SJt=k`V4$PXu|j@2e?3(BCc7_i`UcK1F1%T( z(+_DprBzL+ijKERM1j1xc=(D&kTt)aEp4xjL)^0Du)b26$5bFQRai0eF6y9n5X|xDmqX*ByiE45aDxGc^7=qYZ zZz^YDl1k)E0|Es`-~F)4W&2>-t+pyO0M$uoV@XK~odZaqNQ72V;LvL69FU7Jh|x)Y z6))yvl(3b2q+BAipgdr_lxI4^=QjLAI#9dt-xviONW;1<-Ptx4{r6G^vdfrOK8(2{v7>SYFPr zso4BmPCCgrt;s|+)yOOFSZ>~gas&kxc7m$E5GZ^zX)wimfjI~V+EBqb$R}?+Xl)^9 zt;`9NwKtIRt!5!MotG?mCJ+P$A>+#~Lv8<(jPWe&15uG6`FRf2Fpd|){u1_9Q*m|u zvg}sXJxgH%pBo!Uv#X+R_K Wi{Erh8#e^bF|&?lXSN?Mxbg$SEnS)b literal 0 HcmV?d00001