@fiscozen/icons 0.2.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,380 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import FzIconBackground from '../FzIconBackground.vue'
4
+
5
+ vi.mock('@awesome.me/kit-8137893ad3/icons', () => ({
6
+ byPrefixAndName: {
7
+ fas: { bell: ['fas', 'bell'], 'user-circle': ['fas', 'user-circle'] },
8
+ far: { bell: ['far', 'bell'], 'user-circle': ['far', 'user-circle'] },
9
+ fal: { bell: ['fal', 'bell'] },
10
+ fat: { bell: ['fat', 'bell'] },
11
+ fad: { bell: ['fad', 'bell'] },
12
+ fass: { bell: ['fass', 'bell'] },
13
+ fasr: { bell: ['fasr', 'bell'] },
14
+ fasl: { bell: ['fasl', 'bell'] },
15
+ fast: { bell: ['fast', 'bell'] },
16
+ fak: { bell: ['fak', 'bell'] }
17
+ }
18
+ }))
19
+
20
+ const mockFontAwesomeIcon = {
21
+ name: 'FontAwesomeIcon',
22
+ template: '<svg :class="$attrs.class" data-testid="fa-icon" />',
23
+ props: ['icon', 'size', 'spin']
24
+ }
25
+
26
+ describe('FzIconBackground', () => {
27
+ beforeEach(() => {
28
+ vi.spyOn(console, 'warn').mockImplementation(() => {})
29
+ })
30
+
31
+ const mountOptions = {
32
+ global: {
33
+ stubs: {
34
+ 'font-awesome-icon': mockFontAwesomeIcon
35
+ }
36
+ }
37
+ }
38
+
39
+ // ============================================
40
+ // RENDERING TESTS
41
+ // ============================================
42
+ describe('Rendering', () => {
43
+ it('should render with default props', () => {
44
+ const wrapper = mount(FzIconBackground, {
45
+ props: { name: 'bell' },
46
+ ...mountOptions
47
+ })
48
+ expect(wrapper.exists()).toBe(true)
49
+ expect(wrapper.find('span').exists()).toBe(true)
50
+ })
51
+
52
+ it('should render with name prop', () => {
53
+ const wrapper = mount(FzIconBackground, {
54
+ props: { name: 'bell' },
55
+ ...mountOptions
56
+ })
57
+ const icon = wrapper.find('svg')
58
+ expect(icon.exists()).toBe(true)
59
+ })
60
+
61
+ it('should render correct container size', () => {
62
+ const wrapper = mount(FzIconBackground, {
63
+ props: { name: 'bell', size: 'lg' },
64
+ ...mountOptions
65
+ })
66
+ const container = wrapper.find('span')
67
+ expect(container.classes()).toContain('w-[25px]')
68
+ expect(container.classes()).toContain('h-[25px]')
69
+ })
70
+
71
+ it('should apply custom class when provided', () => {
72
+ const wrapper = mount(FzIconBackground, {
73
+ props: { name: 'bell' },
74
+ attrs: { class: 'custom-class' },
75
+ ...mountOptions
76
+ })
77
+ const container = wrapper.find('span')
78
+ expect(container.classes()).toContain('custom-class')
79
+ })
80
+ })
81
+
82
+ // ============================================
83
+ // PROPS TESTS
84
+ // ============================================
85
+ describe('Props', () => {
86
+ describe('name prop', () => {
87
+ it('should accept string name', () => {
88
+ const wrapper = mount(FzIconBackground, {
89
+ props: { name: 'bell' },
90
+ ...mountOptions
91
+ })
92
+ expect(wrapper.props('name')).toBe('bell')
93
+ })
94
+
95
+ it('should accept array name', () => {
96
+ const wrapper = mount(FzIconBackground, {
97
+ props: { name: ['fas', 'bell'] },
98
+ ...mountOptions
99
+ })
100
+ expect(wrapper.props('name')).toEqual(['fas', 'bell'])
101
+ })
102
+ })
103
+
104
+ describe('size prop', () => {
105
+ it.each([
106
+ ['xs', 'size-[12.5px]', 'h-[10px]'],
107
+ ['sm', 'w-[15px]', 'h-[12px]'],
108
+ ['md', 'w-[20px]', 'h-[16px]'],
109
+ ['lg', 'w-[25px]', 'h-[20px]'],
110
+ ['xl', 'w-[32px]', 'h-[24px]'],
111
+ ['2xl', 'w-[40px]', 'h-[32px]']
112
+ ])('should apply correct classes for %s size', (size, containerClass, iconClass) => {
113
+ const wrapper = mount(FzIconBackground, {
114
+ props: { name: 'bell', size: size as 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' },
115
+ ...mountOptions
116
+ })
117
+ const container = wrapper.find('span')
118
+ expect(container.classes()).toContain(containerClass)
119
+ const iconElement = wrapper.find('[data-testid="fa-icon"]')
120
+ const classAttr = iconElement.attributes('class') || ''
121
+ expect(classAttr.includes(iconClass) || iconElement.classes().includes(iconClass)).toBe(true)
122
+ })
123
+
124
+ it('should default to lg size', () => {
125
+ const wrapper = mount(FzIconBackground, {
126
+ props: { name: 'bell' },
127
+ ...mountOptions
128
+ })
129
+ const container = wrapper.find('span')
130
+ expect(container.classes()).toContain('w-[25px]')
131
+ expect(container.classes()).toContain('h-[25px]')
132
+ })
133
+ })
134
+
135
+ describe('variant prop', () => {
136
+ it('should default to far variant', () => {
137
+ const wrapper = mount(FzIconBackground, {
138
+ props: { name: 'bell' },
139
+ ...mountOptions
140
+ })
141
+ expect(wrapper.props('variant')).toBe('far')
142
+ })
143
+
144
+ it.each([['fas'], ['far'], ['fal'], ['fat'], ['fad']])(
145
+ 'should accept %s variant',
146
+ (variant) => {
147
+ const wrapper = mount(FzIconBackground, {
148
+ props: { name: 'bell', variant: variant as 'fas' | 'far' | 'fal' | 'fat' | 'fad' },
149
+ ...mountOptions
150
+ })
151
+ expect(wrapper.props('variant')).toBe(variant)
152
+ }
153
+ )
154
+ })
155
+
156
+ describe('spin prop', () => {
157
+ it('should not spin by default', () => {
158
+ const wrapper = mount(FzIconBackground, {
159
+ props: { name: 'bell' },
160
+ ...mountOptions
161
+ })
162
+ const spinProp = wrapper.props('spin')
163
+ expect(spinProp === undefined || spinProp === false).toBe(true)
164
+ })
165
+
166
+ it('should apply spin when true', () => {
167
+ const wrapper = mount(FzIconBackground, {
168
+ props: { name: 'bell', spin: true },
169
+ ...mountOptions
170
+ })
171
+ expect(wrapper.props('spin')).toBe(true)
172
+ const fontAwesomeComponent = wrapper.findComponent({ name: 'FontAwesomeIcon' })
173
+ expect(fontAwesomeComponent.exists()).toBe(true)
174
+ expect(fontAwesomeComponent.props('spin')).toBe(true)
175
+ })
176
+ })
177
+
178
+ describe('backgroundColor prop', () => {
179
+ it('should default to core-white', () => {
180
+ const wrapper = mount(FzIconBackground, {
181
+ props: { name: 'bell' },
182
+ ...mountOptions
183
+ })
184
+ expect(wrapper.props('backgroundColor')).toBe('core-white')
185
+ })
186
+
187
+ it('should apply background class from backgroundColor', () => {
188
+ const wrapper = mount(FzIconBackground, {
189
+ props: { name: 'bell', backgroundColor: 'grey-100' },
190
+ ...mountOptions
191
+ })
192
+ const container = wrapper.find('span')
193
+ expect(container.classes()).toContain('bg-grey-100')
194
+ })
195
+
196
+ it('should apply box-content, padding and rounded-full', () => {
197
+ const wrapper = mount(FzIconBackground, {
198
+ props: { name: 'bell' },
199
+ ...mountOptions
200
+ })
201
+ const container = wrapper.find('span')
202
+ expect(container.classes()).toContain('box-content')
203
+ expect(container.classes()).toContain('p-8')
204
+ expect(container.classes()).toContain('rounded-full')
205
+ })
206
+ })
207
+ })
208
+
209
+ // ============================================
210
+ // CSS CLASSES TESTS
211
+ // ============================================
212
+ describe('CSS Classes', () => {
213
+ it('should apply static base classes from FzIcon', () => {
214
+ const wrapper = mount(FzIconBackground, {
215
+ props: { name: 'bell' },
216
+ ...mountOptions
217
+ })
218
+ const container = wrapper.find('span')
219
+ expect(container.classes()).toContain('flex')
220
+ expect(container.classes()).toContain('items-center')
221
+ expect(container.classes()).toContain('justify-center')
222
+ })
223
+
224
+ it('should apply background wrapper classes', () => {
225
+ const wrapper = mount(FzIconBackground, {
226
+ props: { name: 'bell' },
227
+ ...mountOptions
228
+ })
229
+ const container = wrapper.find('span')
230
+ expect(container.classes()).toContain('box-content')
231
+ expect(container.classes()).toContain('p-8')
232
+ expect(container.classes()).toContain('rounded-full')
233
+ expect(container.classes()).toContain('bg-core-white')
234
+ })
235
+
236
+ it('should apply size-specific container classes', () => {
237
+ const wrapper = mount(FzIconBackground, {
238
+ props: { name: 'bell', size: 'md' },
239
+ ...mountOptions
240
+ })
241
+ const container = wrapper.find('span')
242
+ expect(container.classes()).toContain('w-[20px]')
243
+ expect(container.classes()).toContain('h-[20px]')
244
+ })
245
+
246
+ it('should apply size-specific icon classes', () => {
247
+ const wrapper = mount(FzIconBackground, {
248
+ props: { name: 'bell', size: 'xl' },
249
+ ...mountOptions
250
+ })
251
+ const fontAwesomeComponent = wrapper.findComponent({ name: 'FontAwesomeIcon' })
252
+ expect(fontAwesomeComponent.exists()).toBe(true)
253
+ const icon = wrapper.find('[data-testid="fa-icon"]')
254
+ const classAttr = icon.attributes('class') || ''
255
+ expect(classAttr.includes('h-[24px]') || icon.classes().includes('h-[24px]')).toBe(true)
256
+ })
257
+ })
258
+
259
+ // ============================================
260
+ // ACCESSIBILITY TESTS
261
+ // ============================================
262
+ describe('Accessibility', () => {
263
+ describe('ARIA attributes', () => {
264
+ it('should have icon rendered for decorative use', () => {
265
+ const wrapper = mount(FzIconBackground, {
266
+ props: { name: 'bell' },
267
+ ...mountOptions
268
+ })
269
+ const icon = wrapper.find('svg')
270
+ expect(icon.exists()).toBe(true)
271
+ })
272
+
273
+ it('should support aria-label when provided', () => {
274
+ const wrapper = mount(FzIconBackground, {
275
+ props: { name: 'bell' },
276
+ attrs: { 'aria-label': 'Notification bell' },
277
+ ...mountOptions
278
+ })
279
+ const container = wrapper.find('span')
280
+ expect(container.attributes('aria-label')).toBe('Notification bell')
281
+ })
282
+
283
+ it('should support role="img" when accessible', () => {
284
+ const wrapper = mount(FzIconBackground, {
285
+ props: { name: 'bell' },
286
+ attrs: { role: 'img', 'aria-label': 'Notification bell' },
287
+ ...mountOptions
288
+ })
289
+ const container = wrapper.find('span')
290
+ expect(container.attributes('role')).toBe('img')
291
+ })
292
+ })
293
+
294
+ describe('Decorative elements', () => {
295
+ it('should render icon without accessibility attributes when decorative', () => {
296
+ const wrapper = mount(FzIconBackground, {
297
+ props: { name: 'bell' },
298
+ ...mountOptions
299
+ })
300
+ const container = wrapper.find('span')
301
+ expect(container.attributes('role')).toBe('presentation')
302
+ expect(container.attributes('aria-label')).toBeUndefined()
303
+ })
304
+ })
305
+ })
306
+
307
+ // ============================================
308
+ // EDGE CASES
309
+ // ============================================
310
+ describe('Edge Cases', () => {
311
+ it('should handle different icon name formats', () => {
312
+ const wrapper = mount(FzIconBackground, {
313
+ props: { name: 'user-circle' },
314
+ ...mountOptions
315
+ })
316
+ expect(wrapper.exists()).toBe(true)
317
+ })
318
+
319
+ it('should handle array icon format', () => {
320
+ const wrapper = mount(FzIconBackground, {
321
+ props: { name: ['fas', 'bell'] },
322
+ ...mountOptions
323
+ })
324
+ expect(wrapper.exists()).toBe(true)
325
+ })
326
+ })
327
+
328
+ // ============================================
329
+ // SNAPSHOTS
330
+ // ============================================
331
+ describe('Snapshots', () => {
332
+ it('should match snapshot - default state', () => {
333
+ const wrapper = mount(FzIconBackground, {
334
+ props: { name: 'bell' },
335
+ ...mountOptions
336
+ })
337
+ expect(wrapper.html()).toMatchSnapshot()
338
+ })
339
+
340
+ it('should match snapshot - small size', () => {
341
+ const wrapper = mount(FzIconBackground, {
342
+ props: { name: 'bell', size: 'sm' },
343
+ ...mountOptions
344
+ })
345
+ expect(wrapper.html()).toMatchSnapshot()
346
+ })
347
+
348
+ it('should match snapshot - large size', () => {
349
+ const wrapper = mount(FzIconBackground, {
350
+ props: { name: 'bell', size: 'xl' },
351
+ ...mountOptions
352
+ })
353
+ expect(wrapper.html()).toMatchSnapshot()
354
+ })
355
+
356
+ it('should match snapshot - with spin', () => {
357
+ const wrapper = mount(FzIconBackground, {
358
+ props: { name: 'bell', spin: true },
359
+ ...mountOptions
360
+ })
361
+ expect(wrapper.html()).toMatchSnapshot()
362
+ })
363
+
364
+ it('should match snapshot - with variant', () => {
365
+ const wrapper = mount(FzIconBackground, {
366
+ props: { name: 'bell', variant: 'fas' },
367
+ ...mountOptions
368
+ })
369
+ expect(wrapper.html()).toMatchSnapshot()
370
+ })
371
+
372
+ it('should match snapshot - with backgroundColor', () => {
373
+ const wrapper = mount(FzIconBackground, {
374
+ props: { name: 'bell', backgroundColor: 'grey-100' },
375
+ ...mountOptions
376
+ })
377
+ expect(wrapper.html()).toMatchSnapshot()
378
+ })
379
+ })
380
+ })
@@ -0,0 +1,11 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`FzIcon > Snapshots > should match snapshot - default state 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px]"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
4
+
5
+ exports[`FzIcon > Snapshots > should match snapshot - large size 1`] = `"<span role="presentation" class="flex items-center justify-center w-[32px] h-[32px]"><svg class="h-[24px]" data-testid="fa-icon"></svg></span>"`;
6
+
7
+ exports[`FzIcon > Snapshots > should match snapshot - small size 1`] = `"<span role="presentation" class="flex items-center justify-center w-[15px] h-[15px]"><svg class="h-[12px]" data-testid="fa-icon"></svg></span>"`;
8
+
9
+ exports[`FzIcon > Snapshots > should match snapshot - with spin 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px]"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
10
+
11
+ exports[`FzIcon > Snapshots > should match snapshot - with variant 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px]"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
@@ -0,0 +1,13 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`FzIconBackground > Snapshots > should match snapshot - default state 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px] box-content p-8 rounded-full bg-core-white"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
4
+
5
+ exports[`FzIconBackground > Snapshots > should match snapshot - large size 1`] = `"<span role="presentation" class="flex items-center justify-center w-[32px] h-[32px] box-content p-8 rounded-full bg-core-white"><svg class="h-[24px]" data-testid="fa-icon"></svg></span>"`;
6
+
7
+ exports[`FzIconBackground > Snapshots > should match snapshot - small size 1`] = `"<span role="presentation" class="flex items-center justify-center w-[15px] h-[15px] box-content p-8 rounded-full bg-core-white"><svg class="h-[12px]" data-testid="fa-icon"></svg></span>"`;
8
+
9
+ exports[`FzIconBackground > Snapshots > should match snapshot - with backgroundColor 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px] box-content p-8 rounded-full bg-grey-100"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
10
+
11
+ exports[`FzIconBackground > Snapshots > should match snapshot - with spin 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px] box-content p-8 rounded-full bg-core-white"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
12
+
13
+ exports[`FzIconBackground > Snapshots > should match snapshot - with variant 1`] = `"<span role="presentation" class="flex items-center justify-center w-[25px] h-[25px] box-content p-8 rounded-full bg-core-white"><svg class="h-[20px]" data-testid="fa-icon"></svg></span>"`;
package/src/index.ts CHANGED
@@ -2,15 +2,17 @@ import { Plugin } from 'vue'
2
2
  import { library } from '@fortawesome/fontawesome-svg-core'
3
3
  import { all } from '@awesome.me/kit-8137893ad3/icons'
4
4
  import FzIcon from './FzIcon.vue'
5
+ import FzIconBackground from './FzIconBackground.vue'
5
6
 
6
7
  const IconPlugin : Plugin = {
7
8
  install(app) {
8
9
  // @ts-ignore
9
10
  library.add(...all)
10
11
  app.component('fz-icon', FzIcon)
12
+ app.component('fz-icon-background', FzIconBackground)
11
13
  }
12
14
  }
13
15
 
14
- export { FzIcon, IconPlugin }
16
+ export { FzIcon, FzIconBackground, IconPlugin }
15
17
 
16
- export type { IconVariant, IconSize, IconProps } from './types'
18
+ export type { IconVariant, IconSize, IconProps, IconBackgroundProps } from './types'
package/src/types.ts CHANGED
@@ -8,4 +8,8 @@ interface IconProps {
8
8
  spin?: boolean;
9
9
  }
10
10
 
11
- export type { IconVariant, IconSize, IconProps }
11
+ interface IconBackgroundProps extends IconProps {
12
+ backgroundColor?: string;
13
+ }
14
+
15
+ export type { IconVariant, IconSize, IconProps, IconBackgroundProps }