diff --git a/app/components/Package/WeeklyDownloadStats.vue b/app/components/Package/WeeklyDownloadStats.vue index 67a797e78..cb17b9e44 100644 --- a/app/components/Package/WeeklyDownloadStats.vue +++ b/app/components/Package/WeeklyDownloadStats.vue @@ -11,13 +11,6 @@ const props = defineProps<{ const chartModal = useModal('chart-modal') const isChartModalOpen = shallowRef(false) -async function openChartModal() { - isChartModalOpen.value = true - // ensure the component renders before opening the dialog - await nextTick() - await nextTick() - chartModal.open() -} const { fetchPackageDownloadEvolution } = useCharts() @@ -85,10 +78,23 @@ const pulseColor = computed(() => { }) const weeklyDownloads = shallowRef([]) +const isLoadingWeeklyDownloads = shallowRef(true) +const hasWeeklyDownloads = computed(() => weeklyDownloads.value.length > 0) + +async function openChartModal() { + if (!hasWeeklyDownloads.value) return + + isChartModalOpen.value = true + // ensure the component renders before opening the dialog + await nextTick() + await nextTick() + chartModal.open() +} async function loadWeeklyDownloads() { if (!import.meta.client) return + isLoadingWeeklyDownloads.value = true try { const result = await fetchPackageDownloadEvolution( () => props.packageName, @@ -98,6 +104,8 @@ async function loadWeeklyDownloads() { weeklyDownloads.value = (result as WeeklyDownloadPoint[]) ?? [] } catch { weeklyDownloads.value = [] + } finally { + isLoadingWeeklyDownloads.value = false } } @@ -201,6 +209,7 @@ const config = computed(() => {
- - - - - +

+ {{ $t('package.downloads.no_data') }} +

- + ({ + mockFetchPackageDownloadEvolution: vi.fn(), +})) + +mockNuxtImport('useCharts', () => { + return () => ({ + fetchPackageDownloadEvolution: (...args: unknown[]) => + mockFetchPackageDownloadEvolution(...args), + }) +}) + +vi.mock('vue-data-ui/vue-ui-sparkline', () => ({ + VueUiSparkline: defineComponent({ + name: 'VueUiSparkline', + inheritAttrs: false, + setup(_, { attrs, slots }) { + return () => h('div', { class: attrs.class }, slots.default?.() ?? []) + }, + }), +})) + +import PackageWeeklyDownloadStats from '~/components/Package/WeeklyDownloadStats.vue' + +describe('PackageWeeklyDownloadStats', () => { + const baseProps = { + packageName: 'test-package', + createdIso: '2026-02-05T00:00:00.000Z', + } + + it('hides the section when weekly downloads are empty', async () => { + mockFetchPackageDownloadEvolution.mockReset() + mockFetchPackageDownloadEvolution.mockResolvedValue([]) + + const component = await mountSuspended(PackageWeeklyDownloadStats, { + props: baseProps, + }) + + expect(component.text()).toContain('Weekly Downloads') + expect(component.text()).toContain('No download data available') + }) + + it('shows the section when weekly downloads exist', async () => { + mockFetchPackageDownloadEvolution.mockReset() + mockFetchPackageDownloadEvolution.mockResolvedValue([ + { + weekStart: '2026-01-01', + weekEnd: '2026-01-07', + timestampStart: 1767225600000, + timestampEnd: 1767744000000, + downloads: 42, + }, + ]) + + const component = await mountSuspended(PackageWeeklyDownloadStats, { + props: baseProps, + }) + + expect(component.text()).toContain('Weekly Downloads') + expect(component.text()).not.toContain('No download data available') + }) +})