Skip to content

Commit

Permalink
feat(Avatar): render img tag on ssr (unovue#776)
Browse files Browse the repository at this point in the history
* feat: render img tag on ssr

* fix: self  closing tags causing hydration issue

* test: update avatar test

* test: prevent warning of missing prop
  • Loading branch information
zernonia authored Mar 20, 2024
1 parent e50e57f commit f7d611c
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 13 deletions.
20 changes: 10 additions & 10 deletions packages/radix-vue/src/Avatar/Avatar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Avatar from './story/_Avatar.vue'
import type { VueWrapper } from '@vue/test-utils'
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import { findByAltText, findByRole, findByText } from '@testing-library/vue'
import { findByAltText, findByText, queryByText, waitForElementToBeRemoved } from '@testing-library/vue'

const FALLBACK = 'CT'
const DELAY = 350
Expand Down Expand Up @@ -35,23 +35,23 @@ describe('given an Avatar with fallback and a working image', async () => {
expect(wrapper.html()).includes(FALLBACK)
})

it('should not render the image initially', () => {
it('should render the image, but show `display:none` initially', () => {
const image = wrapper.find('img')
expect(image.exists()).toBeFalsy()
})

it('should render the image after it has loaded', async () => {
const image = await findByRole(wrapper.element as HTMLElement, 'img')

expect(image).toBeTruthy()
expect(image.exists()).toBeTruthy()
expect(image.element).toHaveStyle({ display: 'none' })
})

it('should have alt text on the image', async () => {
const image = await findByAltText(wrapper.element as HTMLElement, 'Colm Tuite')
expect(image).toBeTruthy()
})

it('should render as snapshot', () => {
it('should match before image loaded snapshot', () => {
expect(wrapper.html()).toMatchSnapshot()
})

it('should match after image loaded snapshot', async () => {
await waitForElementToBeRemoved(() => queryByText(wrapper.element as HTMLElement, 'CT'))
expect(wrapper.html()).toMatchSnapshot()
})
})
Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/Avatar/AvatarImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ watch(

<template>
<Primitive
v-if="imageLoadingStatus === 'loaded'"
v-show="imageLoadingStatus === 'loaded'"
role="img"
:as-child="asChild"
:as="as"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`given an Avatar with fallback and a working image > should render as snapshot 1`] = `"<span class="bg-blackA3 inline-flex h-[45px] w-[45px] select-none items-center justify-center overflow-hidden rounded-full align-middle"><img role="img" src="https://images.unsplash.com/photo-1492633423870-43d1cd2775eb?&amp;w=128&amp;h=128&amp;dpr=2&amp;q=80" class="h-full w-full rounded-[inherit] object-cover" alt="Colm Tuite"><!--v-if--></span>"`;
exports[`given an Avatar with fallback and a working image > should match after image loaded snapshot 1`] = `"<span class="bg-blackA3 inline-flex h-[45px] w-[45px] select-none items-center justify-center overflow-hidden rounded-full align-middle"><img role="img" src="https://images.unsplash.com/photo-1492633423870-43d1cd2775eb?&amp;w=128&amp;h=128&amp;dpr=2&amp;q=80" class="h-full w-full rounded-[inherit] object-cover" alt="Colm Tuite" style=""><!--v-if--></span>"`;
exports[`given an Avatar with fallback and a working image > should match before image loaded snapshot 1`] = `"<span class="bg-blackA3 inline-flex h-[45px] w-[45px] select-none items-center justify-center overflow-hidden rounded-full align-middle"><img role="img" src="https://images.unsplash.com/photo-1492633423870-43d1cd2775eb?&amp;w=128&amp;h=128&amp;dpr=2&amp;q=80" class="h-full w-full rounded-[inherit] object-cover" alt="Colm Tuite" style="display: none;"><span class="text-violet11 leading-1 flex h-full w-full items-center justify-center bg-white text-[15px] font-medium"> CT </span></span>"`;
5 changes: 5 additions & 0 deletions packages/radix-vue/src/Primitive/Primitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export const Primitive = defineComponent({
setup(props, { attrs, slots }) {
const asTag = props.asChild ? 'template' : props.as

// For self closing tags, don't provide default slots because of hydration issue
const SELT_CLOSING_TAGS = ['area', 'img', 'input']
if (typeof asTag === 'string' && SELT_CLOSING_TAGS.includes(asTag))
return () => h(asTag, attrs)

if (asTag !== 'template')
return () => h(props.as, attrs, { default: slots.default })

Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/TagsInput/story/_TagsInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Icon } from '@iconify/vue'
export interface TestProps {
addOnTab?: boolean
addOnBlur: boolean
addOnBlur?: boolean
}
withDefaults(defineProps<TestProps>(), {
Expand Down

0 comments on commit f7d611c

Please sign in to comment.