I am currently testing a Vue component that should display a success icon for 3 seconds when the loading state changes from true to false. I have encountered challenges while trying to write a component test using Vue Testing Library or Vue test utils due to various reasons (such as issues with props in mount/render and differences in watcher behavior). I am contemplating changing my approach by testing a composable instead of directly testing the component, although I anticipate facing similar difficulties. Any suggestions or ideas on how to tackle this?
<script setup lang="ts">
interface Props {
loading?: boolean;
label?: string;
error?: boolean;
loadingSuccessText?: string;
loadingSuccessIcon?: string;
}
const props = withDefaults(defineProps<Props>(), {
loading: false,
label: "button",
error: false,
loadingSuccessText: "Success",
loadingSuccessIcon: "circle-check",
});
const loadingTimeoutId = ref<number | undefined>(undefined);
const clicking = ref(false);
const loading = toRef(props, "loading");
const loadingFinished = computed(() => !!loadingTimeoutId.value);
watch(loading, (newVal, oldVal) => {
if (newVal != oldVal && !newVal) return;
clearTimeout(loadingTimeoutId.value);
loadingTimeoutId.value = setTimeout(() => {
loadingTimeoutId.value = undefined;
}, 3000);
});
</script>
<template>
<button
id="button"
:aria-label="label"
:class="['gradient-button', clicking ? 'gradient-button--clicked' : '']"
@mousedown="clicking = true"
@mouseup="clicking = false"
@mouseleave="clicking = false"
>
<span v-if="loadingFinished && !loading && !error">
{{ loadingSuccessText }}
<FontAwesomeIcon :icon="loadingSuccessIcon" data-testid="success" />
</span>
<slot v-else-if="!loading"></slot>
<span v-else class="loader loader--small" data-testid="spinner"></span>
</button>
</template>