2

im trying to write tests with Vitest for my vue3 component

this is my component code:

<script lang="ts" setup>
import { reactive, computed,  ref, onMounted } from 'vue'
import { formatSubscribers } from '../../helpers/formatSubscribers'
import { formatDescription } from '../../helpers/formatDescription'
import { formatViews } from '../../helpers/formatViews'
import type {PropType} from 'vue'
import { useHistory } from '../../stores/history'
import type { IVideo } from '@/types/video'

const historyStore = useHistory()

interface State {
  readMore: boolean
}

const state = reactive<State>({
  readMore: false
})

const props = defineProps({
  videoId: { type: String, required: true },
  video: { type: Object as PropType<IVideo>, required: true }
})

const embedUrl = computed(
  () => `https://www.youtube.com/embed/${props.videoId}?autoplay=1&showinfo=1&mute=0`
)

const channelThumbnailUrl = computed(() => props.video?.channel?.thumbnail?.url)

const formattedSubscriberCount = computed(() => {
  const subscriberCount = props.video?.channel?.subscriberCount
  return formatSubscribers(subscriberCount) + ' inscritos'
})

const descriptionHtml = computed(() => {
  return formatDescription(props.video.description, state.readMore)
})

const readMoreButtonLabel = computed(() => {
  return state.readMore ? 'ver menos' : 'ver mais'
})

function toggleReadMore() {
  state.readMore = !state.readMore
}

function addVideo() {
  const history = historyStore.getHistory
  if (history.length === 0 || history[0].id !== props.video.id) {
    historyStore.addVideo(props.video)
  }
}

const videoPlayer = ref<HTMLIFrameElement | null>(null)
onMounted(() => {
  videoPlayer.value?.addEventListener('load', addVideo)
})
</script>

<template>
  <div class="video">
    <div class="iframe-container">
      <iframe
        ref="videoPlayer"
        :src="embedUrl"
        frameborder="0"
        allowfullscreen
        v-if="video"
      ></iframe>
    </div>
    <h1 class="video__name">{{ video.title }}</h1>
    <div class="video__channel">
      <img :src="channelThumbnailUrl" :alt="video.channel.title" />
      <div>
        <p>{{ video.channel.title }}</p>
        <p>{{ formattedSubscriberCount }}</p>
      </div>
    </div>
    <div class="video__description">
      <p>{{ formatViews(video.viewCount) }}</p>
      <p v-html="descriptionHtml"></p>
      <button @click="toggleReadMore">{{ readMoreButtonLabel }}</button>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.iframe-container {
  position: relative;
  overflow: hidden;
  width: 100%;
  padding-top: 56.25%;

  /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
  iframe {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    width: 100%;
    height: 100%;
  }
}

.video {
  padding: 64px 0;

  @media (min-width: 768px) {
    padding: 128px 0;
  }

  &__name {
    margin-top: 14px;
    margin-bottom: 14px;
    font-size: 20px;
  }

  &__channel {
    display: flex;
    gap: 14px;
    margin-bottom: 14px;

    img {
      border-radius: 100%;
      width: 40px;
      height: 40px;
    }
  }

  &__description {
    padding: 14px;
    border-radius: 8px;
    background-color: #282828;
    p:first-of-type {
      margin-bottom: 14px;
    }
    button {
      height: 48px;
      padding: 8px;
      margin-top: 14px;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      color: inherit;
      background-color: transparent;
      background-color: hsla(0, 0%, 100%, 0.08);
      border: 1px solid hsl(0, 0%, 18.82%);
      text-transform: capitalize;
      &:hover {
        background-color: hsla(0, 0%, 100%, 0.16);
      }
    }
  }
}
</style>

and this is my test:

import { mount } from '@vue/test-utils'
import { describe, it,expect } from 'vitest'
import VideoPlayer from '@/components/UI/VideoPlayer.vue'
import type { IVideo } from '@/types/video';
import { formatViews } from '@/helpers/formatViews';

const videoMock: IVideo = {
  id: 'abc123',
  title: 'Test Video',
  description: 'This is a test video.',
  thumbnail: 'https://example.com/thumbnail.png',
  channel: {
    id: 'def456',
    title: 'Test Channel',
    thumbnail: {
      url: 'https://example.com/channel_thumbnail.png',
      width: 100,
      height: 100,
    },
    subscriberCount: '1000',
  },
  viewCount: '100',
  duration: '1:00',
};

describe('Video', () => {
  it('displays the video title', () => {
    const wrapper = mount(VideoPlayer, { props: { video: videoMock, videoId: '1' } })
    expect(wrapper.find('.video__name').text()).toBe('Test Video')
  })

  it('displays the channel title and subscriber count', () => {
    const wrapper = mount(VideoPlayer, { props: { video: videoMock, videoId: '1' } })
    expect(wrapper.find('.video__channel p:first-child').text()).toBe('Test Channel')
    expect(wrapper.find('.video__channel p:last-child').text()).toBe('1,000')
  })

})

the error that i got:

TypeError: $setup.formatViews is not a function

❯ Proxy._sfc_render src/components/UI/VideoPlayer.vue:81:13

I don't know if I need to mock $setup.formatViews. this is the problem? how do I do it?

0

1 Answer 1

0

I just changed the implementation of formatSubscribers, made a computed property using the function, maybe it worked as I'm not getting this error anymore, I just need to finish the test

Sign up to request clarification or add additional context in comments.

1 Comment

yes that really worked, I don't know if there is another way

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.