From af57300a555f93cb71d940e8808439d532d90d80 Mon Sep 17 00:00:00 2001 From: Bence Markus Date: Sun, 1 Dec 2024 12:44:34 +0100 Subject: [PATCH] test: new tests added --- src/components/bo_avatar/BoAvatar.vue | 38 +-- .../__stories__/bo_avatar.stories.ts | 24 +- .../__snapshots__/bo_avatar.test.ts.snap | 3 + .../bo_avatar/__tests__/bo_avatar.test.ts | 305 ++++++++++++++++++ src/components/bo_avatar/constants.ts | 8 - src/components/bo_avatar/types.ts | 5 +- .../bo_loading_spinner.test.ts.snap | 4 +- 7 files changed, 341 insertions(+), 46 deletions(-) create mode 100644 src/components/bo_avatar/__tests__/__snapshots__/bo_avatar.test.ts.snap create mode 100644 src/components/bo_avatar/__tests__/bo_avatar.test.ts diff --git a/src/components/bo_avatar/BoAvatar.vue b/src/components/bo_avatar/BoAvatar.vue index 2845c22..625996e 100644 --- a/src/components/bo_avatar/BoAvatar.vue +++ b/src/components/bo_avatar/BoAvatar.vue @@ -19,6 +19,7 @@ class="bo-avatar__initials flex items-center justify-center" > import { BoFontSize, BoText } from '@/components/bo_text'; +import { BoSize } from '@/data/bo_size.constant'; import { StringUtils, TailwindUtils } from '@/utils'; import { computed, toRefs, type StyleValue } from 'vue'; -import { BoAvatarShape, BoAvatarSize, BoAvatarType } from './constants'; +import { BoAvatarShape, BoAvatarType } from './constants'; import type { BoAvatarProps } from './types'; const props = withDefaults(defineProps(), { type: () => BoAvatarType.initials, - size: () => BoAvatarSize.default, + size: () => BoSize.default, shape: () => BoAvatarShape.rounded, }); @@ -81,15 +83,15 @@ const showDefaultAvatar = computed(() => { const labelSize = computed(() => { switch (size.value) { - case BoAvatarSize.extra_small: + case BoSize.extra_small: return BoFontSize.extra_small; - case BoAvatarSize.small: + case BoSize.small: return BoFontSize.small; - case BoAvatarSize.large: + case BoSize.large: return BoFontSize.default; - case BoAvatarSize.extra_large: + case BoSize.extra_large: return BoFontSize.body; - case BoAvatarSize.default: + case BoSize.default: default: return BoFontSize.default; } @@ -105,23 +107,23 @@ const containerStyle = computed(() => { return {}; }); -const tailwindCssSizeClasses = computed(() => { +const avatarSizeClasses = computed(() => { switch (size.value) { - case BoAvatarSize.extra_small: + case BoSize.extra_small: return /*tw*/ 'size-6'; - case BoAvatarSize.small: + case BoSize.small: return /*tw*/ 'size-8'; - case BoAvatarSize.large: + case BoSize.large: return /*tw*/ 'size-12'; - case BoAvatarSize.extra_large: + case BoSize.extra_large: return /*tw*/ 'size-14'; - case BoAvatarSize.default: + case BoSize.default: default: return /*tw*/ 'size-10'; } }); -const tailwindCssShapeClasses = computed(() => { +const avatarShapeClasses = computed(() => { switch (shape.value) { case BoAvatarShape.circle: return /*tw*/ 'rounded-full'; @@ -134,7 +136,7 @@ const tailwindCssShapeClasses = computed(() => { } }); -const tailwindCssContainerDefaultClasses = computed(() => { +const avatarContainerDefaultClasses = computed(() => { const colors = [ /*tw*/ 'bg-blue-600', /*tw*/ 'bg-green-600', @@ -165,9 +167,9 @@ const tailwindCssContainerDefaultClasses = computed(() => { const containerClasses = computed(() => { return TailwindUtils.merge( - tailwindCssContainerDefaultClasses.value, - tailwindCssShapeClasses.value, - tailwindCssSizeClasses.value, + avatarContainerDefaultClasses.value, + avatarShapeClasses.value, + avatarSizeClasses.value, ); }); diff --git a/src/components/bo_avatar/__stories__/bo_avatar.stories.ts b/src/components/bo_avatar/__stories__/bo_avatar.stories.ts index 1f5a5b3..e4a850c 100644 --- a/src/components/bo_avatar/__stories__/bo_avatar.stories.ts +++ b/src/components/bo_avatar/__stories__/bo_avatar.stories.ts @@ -1,12 +1,7 @@ -import { - BoAvatar, - BoAvatarShape, - BoAvatarSize, - BoAvatarType, -} from '@/components/bo_avatar'; +import { BoAvatar, BoAvatarShape, BoAvatarType } from '@/components/bo_avatar'; +import { BoSize } from '@/data/bo_size.constant'; import { StorybookUtils } from '@/utils'; import type { Meta, StoryObj } from '@storybook/vue3'; -import ImageAvatar from './img_avatar.png'; const meta = { title: 'Components/bo-avatar', @@ -48,19 +43,16 @@ const meta = { size: { description: 'The size of the avatar', control: { type: 'select' }, - options: Object.values(BoAvatarSize), + options: Object.values(BoSize), table: { category: 'props', subcategory: 'optional', type: { - summary: 'BoAvatarSize', - detail: StorybookUtils.stringEnumFormatter( - BoAvatarSize, - 'BoAvatarSize', - ), + summary: 'BoSize', + detail: StorybookUtils.stringEnumFormatter(BoSize, 'BoSize'), }, }, - defaultValue: BoAvatarSize.default, + defaultValue: BoSize.default, }, shape: { description: 'The shape of the avatar', @@ -145,7 +137,7 @@ export const Image: Story = { args: { type: BoAvatarType.image, imageData: { - src: ImageAvatar, + src: new URL('./img_avatar.png', import.meta.url).href, alt: 'avatar', }, }, @@ -175,7 +167,7 @@ export const Sizes: Story = { render: (args) => ({ components: { BoAvatar }, setup() { - const sizes = Object.values(BoAvatarSize); + const sizes = Object.values(BoSize); return { sizes, ...args }; }, template: ` diff --git a/src/components/bo_avatar/__tests__/__snapshots__/bo_avatar.test.ts.snap b/src/components/bo_avatar/__tests__/__snapshots__/bo_avatar.test.ts.snap new file mode 100644 index 0000000..c2c6101 --- /dev/null +++ b/src/components/bo_avatar/__tests__/__snapshots__/bo_avatar.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`bo_avatar.vue > should match snapshot 1`] = `"
BO
"`; diff --git a/src/components/bo_avatar/__tests__/bo_avatar.test.ts b/src/components/bo_avatar/__tests__/bo_avatar.test.ts new file mode 100644 index 0000000..e6d4dc1 --- /dev/null +++ b/src/components/bo_avatar/__tests__/bo_avatar.test.ts @@ -0,0 +1,305 @@ +import { BoAvatar, BoAvatarShape, BoAvatarType } from '@/components/bo_avatar'; +import { BoText } from '@/components/bo_text'; +import { BoSize } from '@/data/bo_size.constant'; +import { mount } from '@vue/test-utils'; +import { beforeEach, expect, suite, test } from 'vitest'; + +suite('bo_avatar.vue', () => { + test('should match snapshot', () => { + const wrapper = mount(BoAvatar, { + props: { + type: BoAvatarType.initials, + initialsData: { + initials: 'BO', + alt: 'avatar', + }, + shape: BoAvatarShape.rounded, + size: BoSize.default, + colorHex: undefined, + fontColorHex: undefined, + clickable: false, + withDefaultImage: false, + }, + }); + + expect(wrapper.html()).toMatchSnapshot(); + }); + + suite('bo_avatar initials', () => { + let initialWrapper: ReturnType; + + beforeEach(() => { + initialWrapper = mount(BoAvatar, { + props: { + type: BoAvatarType.initials, + initialsData: { + initials: 'BO', + alt: 'avatar', + }, + shape: BoAvatarShape.rounded, + size: BoSize.default, + colorHex: undefined, + fontColorHex: undefined, + clickable: false, + withDefaultImage: false, + }, + }); + }); + + test('should render the initials', () => { + expect(initialWrapper.find('span')).toBeTruthy(); + expect(initialWrapper.find('span').text()).toBe('BO'); + }); + + test('should have alt text added to the initials', () => { + expect( + initialWrapper + .find('.bo-avatar__initials') + .find('span') + .attributes('alt'), + ).toBe('avatar'); + }); + + suite('avatar shapes', () => { + test('should have the default shape', () => { + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-lg', + ); + }); + + test('should be able to change the shape to circle', async () => { + await initialWrapper.setProps({ shape: BoAvatarShape.circle }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-full', + ); + }); + + test('should be able to change the shape to square', async () => { + await initialWrapper.setProps({ shape: BoAvatarShape.square }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-none', + ); + }); + + test('should be able to change the shape to rounded', async () => { + await initialWrapper.setProps({ shape: BoAvatarShape.rounded }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-lg', + ); + }); + }); + + suite('avatar sizes', () => { + test('should have the default size', () => { + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'size-10', + ); + }); + + test('should be able to change the size to extra small', async () => { + await initialWrapper.setProps({ size: BoSize.extra_small }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain('size-6'); + }); + + test('should be able to change the size to small', async () => { + await initialWrapper.setProps({ size: BoSize.small }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain('size-8'); + }); + + test('should be able to change the size to default', async () => { + await initialWrapper.setProps({ size: BoSize.default }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'size-10', + ); + }); + + test('should be able to change the size to large', async () => { + await initialWrapper.setProps({ size: BoSize.large }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'size-12', + ); + }); + + test('should be able to change the size to extra large', async () => { + await initialWrapper.setProps({ size: BoSize.extra_large }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'size-14', + ); + }); + }); + + suite('avatar colors', () => { + test('should have a random default background color if no cusotom one is provided', async () => { + await initialWrapper.setProps({ colorHex: undefined }); + expect(initialWrapper.find('.bo-avatar').classes().join('')).includes( + 'bg-', + ); + }); + + test('should be able to set a custom background color in hex format', async () => { + const colorHex = '#123456'; + await initialWrapper.setProps({ colorHex }); + + const element = initialWrapper.find('.bo-avatar'); + + expect(element.attributes('style')).toBe( + 'background-color: rgb(18, 52, 86);', + ); + }); + + test('should be able to change the font color in hex format', async () => { + const fontColorHex = '#123456'; + await initialWrapper.setProps({ fontColorHex }); + + const element = initialWrapper.findComponent(BoText); + + expect(element.attributes('style')).toBe('color: rgb(18, 52, 86);'); + }); + }); + + suite('avatar clickable', () => { + test('should be able to make the avatar clickable', async () => { + await initialWrapper.setProps({ clickable: true }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'cursor-pointer', + ); + }); + + test('in case the avatar is not clickable, it should have the default cursor', async () => { + await initialWrapper.setProps({ clickable: false }); + expect(initialWrapper.find('.bo-avatar').classes()).toContain( + 'cursor-default', + ); + }); + }); + }); + + suite('bo_avatar image', () => { + let imageWrapper: ReturnType; + + beforeEach(() => { + imageWrapper = mount(BoAvatar, { + props: { + type: BoAvatarType.image, + imageData: { + src: 'https://example.com/image.jpg', + alt: 'avatar', + }, + }, + }); + }); + + suite('avatar with default image', () => { + test('should render the default image', async () => { + await imageWrapper.setProps({ withDefaultImage: true }); + + const element = imageWrapper.find('.bo-avatar__default'); + expect(element.exists()).toBe(true); + }); + + test('should not render this image if the prop is set to false', async () => { + await imageWrapper.setProps({ withDefaultImage: false }); + + const element = imageWrapper.find('.bo-avatar__default'); + expect(element.exists()).toBe(false); + }); + }); + + suite('avatar with image from src', () => { + test('should render the image', async () => { + await imageWrapper.setProps({ + imageData: { src: 'https://example.com/image.jpg', alt: 'avatar' }, + }); + expect(imageWrapper.find('.bo-avatar__image')).toBeTruthy(); + }); + + test('should have the alt text added to the image', async () => { + await imageWrapper.setProps({ + imageData: { src: 'https://example.com/image.jpg', alt: 'avatar' }, + }); + expect(imageWrapper.find('.bo-avatar__image').attributes('alt')).toBe( + 'avatar', + ); + }); + + test('should have the src of the image added to the image', async () => { + await imageWrapper.setProps({ + imageData: { src: 'https://example.com/image.jpg', alt: 'avatar' }, + type: BoAvatarType.image, + }); + + expect(imageWrapper.find('.bo-avatar__image').attributes('src')).toBe( + 'https://example.com/image.jpg', + ); + }); + + suite('avatar image sizes', () => { + test('should have the default size', () => { + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'size-10', + ); + }); + + test('should be able to change the size to extra small', async () => { + await imageWrapper.setProps({ size: BoSize.extra_small }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain('size-6'); + }); + + test('should be able to change the size to small', async () => { + await imageWrapper.setProps({ size: BoSize.small }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain('size-8'); + }); + + test('should be able to change the size to default', async () => { + await imageWrapper.setProps({ size: BoSize.default }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'size-10', + ); + }); + + test('should be able to change the size to large', async () => { + await imageWrapper.setProps({ size: BoSize.large }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'size-12', + ); + }); + + test('should be able to change the size to extra large', async () => { + await imageWrapper.setProps({ size: BoSize.extra_large }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'size-14', + ); + }); + }); + + suite('avatar image shapes', () => { + test('should have the default shape', () => { + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-lg', + ); + }); + + test('should be able to change the shape to circle', async () => { + await imageWrapper.setProps({ shape: BoAvatarShape.circle }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-full', + ); + }); + + test('should be able to change the shape to square', async () => { + await imageWrapper.setProps({ shape: BoAvatarShape.square }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-none', + ); + }); + + test('should be able to change the shape to rounded', async () => { + await imageWrapper.setProps({ shape: BoAvatarShape.rounded }); + expect(imageWrapper.find('.bo-avatar').classes()).toContain( + 'rounded-lg', + ); + }); + }); + }); + }); +}); diff --git a/src/components/bo_avatar/constants.ts b/src/components/bo_avatar/constants.ts index d15f050..6ffa240 100644 --- a/src/components/bo_avatar/constants.ts +++ b/src/components/bo_avatar/constants.ts @@ -1,11 +1,3 @@ -export enum BoAvatarSize { - extra_small = 'extra-small', - small = 'small', - default = 'default', - large = 'large', - extra_large = 'extra-large', -} - export enum BoAvatarShape { circle = 'circle', square = 'square', diff --git a/src/components/bo_avatar/types.ts b/src/components/bo_avatar/types.ts index e1b620e..4cbb2ed 100644 --- a/src/components/bo_avatar/types.ts +++ b/src/components/bo_avatar/types.ts @@ -1,4 +1,5 @@ -import type { BoAvatarShape, BoAvatarSize, BoAvatarType } from './constants'; +import type { BoSize } from '@/data/bo_size.constant'; +import type { BoAvatarShape, BoAvatarType } from './constants'; export type BoAvatarImageProps = { src: string; @@ -15,7 +16,7 @@ export type BoAvatarProps = { initialsData?: BoAvatarInitialsProps; type?: BoAvatarType; shape?: BoAvatarShape; - size?: BoAvatarSize; + size?: BoSize; colorHex?: string; fontColorHex?: string; clickable?: boolean; diff --git a/src/components/bo_loading_spinner/__tests__/__snapshots__/bo_loading_spinner.test.ts.snap b/src/components/bo_loading_spinner/__tests__/__snapshots__/bo_loading_spinner.test.ts.snap index 969f7df..2c0a3f0 100644 --- a/src/components/bo_loading_spinner/__tests__/__snapshots__/bo_loading_spinner.test.ts.snap +++ b/src/components/bo_loading_spinner/__tests__/__snapshots__/bo_loading_spinner.test.ts.snap @@ -1,8 +1,8 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`bo_loading_spinner.vue > should match snapshot 1`] = ` -"
-
+"
+
" `;