diff --git a/src/components/common/UserAvatar.test.ts b/src/components/common/UserAvatar.test.ts new file mode 100644 index 000000000..d844277b9 --- /dev/null +++ b/src/components/common/UserAvatar.test.ts @@ -0,0 +1,106 @@ +import { mount } from '@vue/test-utils' +import Avatar from 'primevue/avatar' +import PrimeVue from 'primevue/config' +import { beforeEach, describe, expect, it } from 'vitest' +import { createApp, nextTick } from 'vue' +import { createI18n } from 'vue-i18n' + +import UserAvatar from './UserAvatar.vue' + +const i18n = createI18n({ + legacy: false, + locale: 'en', + messages: { + en: { + auth: { + login: { + userAvatar: 'User Avatar' + } + } + } + } +}) + +describe('UserAvatar', () => { + beforeEach(() => { + const app = createApp({}) + app.use(PrimeVue) + }) + + const mountComponent = (props: any = {}) => { + return mount(UserAvatar, { + global: { + plugins: [PrimeVue, i18n], + components: { Avatar } + }, + props + }) + } + + it('renders correctly with photo Url', async () => { + const wrapper = mountComponent({ + photoUrl: 'https://example.com/avatar.jpg' + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.exists()).toBe(true) + expect(avatar.props('image')).toBe('https://example.com/avatar.jpg') + expect(avatar.props('icon')).toBeNull() + }) + + it('renders with default icon when no photo Url is provided', () => { + const wrapper = mountComponent({ + photoUrl: undefined + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.exists()).toBe(true) + expect(avatar.props('image')).toBeNull() + expect(avatar.props('icon')).toBe('pi pi-user') + }) + + it('renders with default icon when provided photo Url is null', () => { + const wrapper = mountComponent({ + photoUrl: null + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.exists()).toBe(true) + expect(avatar.props('image')).toBeNull() + expect(avatar.props('icon')).toBe('pi pi-user') + }) + + it('falls back to icon when image fails to load', async () => { + const wrapper = mountComponent({ + photoUrl: 'https://example.com/broken-image.jpg' + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.props('icon')).toBeNull() + + // Simulate image load error + avatar.vm.$emit('error') + await nextTick() + + expect(avatar.props('icon')).toBe('pi pi-user') + }) + + it('uses provided ariaLabel', () => { + const wrapper = mountComponent({ + photoUrl: 'https://example.com/avatar.jpg', + ariaLabel: 'Custom Label' + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.attributes('aria-label')).toBe('Custom Label') + }) + + it('falls back to i18n translation when no ariaLabel is provided', () => { + const wrapper = mountComponent({ + photoUrl: 'https://example.com/avatar.jpg' + }) + + const avatar = wrapper.findComponent(Avatar) + expect(avatar.attributes('aria-label')).toBe('User Avatar') + }) +}) diff --git a/src/components/common/UserAvatar.vue b/src/components/common/UserAvatar.vue new file mode 100644 index 000000000..8fce43d10 --- /dev/null +++ b/src/components/common/UserAvatar.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/dialog/content/setting/UserPanel.vue b/src/components/dialog/content/setting/UserPanel.vue index 2529261d7..9047d8c5a 100644 --- a/src/components/dialog/content/setting/UserPanel.vue +++ b/src/components/dialog/content/setting/UserPanel.vue @@ -5,12 +5,11 @@
-
@@ -87,13 +86,13 @@