1- import { beforeEach , describe , expect , it , vi } from 'vitest'
1+ import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
22import { mountSuspended } from '@nuxt/test-utils/runtime'
3- import type * as FastNpmMeta from 'fast-npm-meta'
43import type * as NpmApi from '~/utils/npm/api'
54import VersionsPage from '~/pages/package/[[org]]/[name]/versions.vue'
65
76// ── Mocks ─────────────────────────────────────────────────────────────────────
87
9- // Phase 1: lightweight version summary (page load)
10- const mockGetVersions = vi . fn ( )
11- vi . mock ( 'fast-npm-meta' , async importOriginal => {
12- const actual = await importOriginal < typeof FastNpmMeta > ( )
13- return {
14- ...actual ,
15- getVersions : ( ...args : unknown [ ] ) => mockGetVersions ( ...args ) ,
16- }
17- } )
18-
198// Phase 2: full metadata (loaded on first group expand)
209const mockFetchAllPackageVersions = vi . fn ( )
2110vi . mock ( '~/utils/npm/api' , async importOriginal => {
@@ -28,6 +17,9 @@ vi.mock('~/utils/npm/api', async importOriginal => {
2817
2918// ── Helpers ───────────────────────────────────────────────────────────────────
3019
20+ /**
21+ * Build a mock response payload matching the fast-npm-meta /versions/ API shape.
22+ */
3123function makeVersionData (
3224 versions : string [ ] ,
3325 distTags : Record < string , string > ,
@@ -42,6 +34,28 @@ function makeVersionData(
4234 }
4335}
4436
37+ /**
38+ * Next response to return from the fast-npm-meta fetch mock.
39+ * Set this before mounting the page.
40+ */
41+ let nextFetchResponse : ReturnType < typeof makeVersionData > | null = null
42+
43+ const originalFetch = globalThis . fetch
44+
45+ function mockFetch ( input : RequestInfo | URL , init ?: RequestInit ) : Promise < Response > {
46+ const url = typeof input === 'string' ? input : input instanceof URL ? input . href : input . url
47+ if ( url . includes ( 'npm.antfu.dev/versions/' ) ) {
48+ const body = nextFetchResponse ?? { distTags : { } , versions : [ ] , time : { } }
49+ return Promise . resolve (
50+ new Response ( JSON . stringify ( body ) , {
51+ status : 200 ,
52+ headers : { 'Content-Type' : 'application/json' } ,
53+ } ) ,
54+ )
55+ }
56+ return originalFetch ( input , init )
57+ }
58+
4559async function mountPage ( route = '/package/test-package/versions' ) {
4660 return mountSuspended ( VersionsPage , { route } )
4761}
@@ -50,20 +64,25 @@ async function mountPage(route = '/package/test-package/versions') {
5064
5165describe ( 'package versions page' , ( ) => {
5266 beforeEach ( ( ) => {
53- mockGetVersions . mockReset ( )
67+ nextFetchResponse = null
5468 mockFetchAllPackageVersions . mockReset ( )
69+ globalThis . fetch = mockFetch as typeof globalThis . fetch
5570 clearNuxtData ( )
5671 } )
5772
73+ afterEach ( ( ) => {
74+ globalThis . fetch = originalFetch
75+ } )
76+
5877 describe ( 'basic rendering' , ( ) => {
5978 it ( 'renders the package name in the header' , async ( ) => {
60- mockGetVersions . mockResolvedValue ( makeVersionData ( [ '1.0.0' ] , { latest : '1.0.0' } ) )
79+ nextFetchResponse = makeVersionData ( [ '1.0.0' ] , { latest : '1.0.0' } )
6180 const component = await mountPage ( )
6281 await vi . waitFor ( ( ) => expect ( component . text ( ) ) . toContain ( 'test-package' ) )
6382 } )
6483
6584 it ( 'renders "Version History" section with total count' , async ( ) => {
66- mockGetVersions . mockResolvedValue ( makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } ) )
85+ nextFetchResponse = makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } )
6786 const component = await mountPage ( )
6887 await vi . waitFor ( ( ) => {
6988 expect ( component . text ( ) ) . toContain ( 'Version History' )
@@ -74,7 +93,7 @@ describe('package versions page', () => {
7493
7594 describe ( 'current tags section' , ( ) => {
7695 it ( 'renders latest version in the featured card' , async ( ) => {
77- mockGetVersions . mockResolvedValue ( makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } ) )
96+ nextFetchResponse = makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } )
7897 const component = await mountPage ( )
7998 await vi . waitFor ( ( ) => {
8099 expect ( component . text ( ) ) . toContain ( 'latest' )
@@ -83,13 +102,11 @@ describe('package versions page', () => {
83102 } )
84103
85104 it ( 'renders non-latest dist-tags in compact list' , async ( ) => {
86- mockGetVersions . mockResolvedValue (
87- makeVersionData ( [ '2.0.0' , '1.0.0' , '1.0.0-beta.1' ] , {
88- latest : '2.0.0' ,
89- stable : '1.0.0' ,
90- beta : '1.0.0-beta.1' ,
91- } ) ,
92- )
105+ nextFetchResponse = makeVersionData ( [ '2.0.0' , '1.0.0' , '1.0.0-beta.1' ] , {
106+ latest : '2.0.0' ,
107+ stable : '1.0.0' ,
108+ beta : '1.0.0-beta.1' ,
109+ } )
93110 const component = await mountPage ( )
94111 await vi . waitFor ( ( ) => {
95112 expect ( component . text ( ) ) . toContain ( 'stable' )
@@ -100,9 +117,7 @@ describe('package versions page', () => {
100117
101118 describe ( 'version history groups' , ( ) => {
102119 it ( 'renders group headers for each major version' , async ( ) => {
103- mockGetVersions . mockResolvedValue (
104- makeVersionData ( [ '2.1.0' , '2.0.0' , '1.0.0' ] , { latest : '2.1.0' } ) ,
105- )
120+ nextFetchResponse = makeVersionData ( [ '2.1.0' , '2.0.0' , '1.0.0' ] , { latest : '2.1.0' } )
106121 const component = await mountPage ( )
107122 await vi . waitFor ( ( ) => {
108123 expect ( component . text ( ) ) . toContain ( '2.x' )
@@ -111,9 +126,7 @@ describe('package versions page', () => {
111126 } )
112127
113128 it ( 'groups 0.x versions by major.minor (not just major)' , async ( ) => {
114- mockGetVersions . mockResolvedValue (
115- makeVersionData ( [ '0.10.1' , '0.10.0' , '0.9.0' ] , { latest : '0.10.1' } ) ,
116- )
129+ nextFetchResponse = makeVersionData ( [ '0.10.1' , '0.10.0' , '0.9.0' ] , { latest : '0.10.1' } )
117130 const component = await mountPage ( )
118131 await vi . waitFor ( ( ) => {
119132 expect ( component . text ( ) ) . toContain ( '0.10.x' )
@@ -124,7 +137,7 @@ describe('package versions page', () => {
124137
125138 describe ( 'group expand / collapse' , ( ) => {
126139 it ( 'expands a group and shows version rows on click' , async ( ) => {
127- mockGetVersions . mockResolvedValue ( makeVersionData ( [ '1.1.0' , '1.0.0' ] , { latest : '1.1.0' } ) )
140+ nextFetchResponse = makeVersionData ( [ '1.1.0' , '1.0.0' ] , { latest : '1.1.0' } )
128141 mockFetchAllPackageVersions . mockResolvedValue ( [
129142 { version : '1.1.0' , time : '2024-01-15T00:00:00.000Z' , hasProvenance : false } ,
130143 { version : '1.0.0' , time : '2024-01-10T00:00:00.000Z' , hasProvenance : false } ,
@@ -141,7 +154,7 @@ describe('package versions page', () => {
141154 } )
142155
143156 it ( 'only fetches full metadata once across multiple group expansions' , async ( ) => {
144- mockGetVersions . mockResolvedValue ( makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } ) )
157+ nextFetchResponse = makeVersionData ( [ '2.0.0' , '1.0.0' ] , { latest : '2.0.0' } )
145158 mockFetchAllPackageVersions . mockResolvedValue ( [
146159 { version : '2.0.0' , time : '2024-01-15T00:00:00.000Z' , hasProvenance : false } ,
147160 { version : '1.0.0' , time : '2024-01-10T00:00:00.000Z' , hasProvenance : false } ,
@@ -163,9 +176,7 @@ describe('package versions page', () => {
163176 describe ( 'version filter' , ( ) => {
164177 it ( 'filters groups by substring match' , async ( ) => {
165178 // Use versions where the filter string "1.0" is unique to the 1.x group
166- mockGetVersions . mockResolvedValue (
167- makeVersionData ( [ '3.0.0' , '2.0.0' , '1.0.0' ] , { latest : '3.0.0' } ) ,
168- )
179+ nextFetchResponse = makeVersionData ( [ '3.0.0' , '2.0.0' , '1.0.0' ] , { latest : '3.0.0' } )
169180 const component = await mountPage ( )
170181 await vi . waitFor ( ( ) => {
171182 expect ( component . text ( ) ) . toContain ( '1.x' )
0 commit comments