Skip to content

Commit 262ed5e

Browse files
committed
perf: improve readme-loaders coverage
1 parent 163dd1d commit 262ed5e

File tree

2 files changed

+174
-17
lines changed

2 files changed

+174
-17
lines changed

app/pages/package/[[org]]/[name].vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const { data: readmeData } = useLazyFetch<ReadmeResponse>(
107107
const version = requestedVersion.value
108108
return version ? `${base}/v/${version}` : base
109109
},
110-
{ default: () => ({ html: '', md: '', playgroundLinks: [], toc: [] }) },
110+
{ default: () => ({ html: '', mdExists: false, playgroundLinks: [], toc: [] }) },
111111
)
112112
113113
const {

test/unit/server/utils/readme-loaders.spec.ts

Lines changed: 173 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import { describe, expect, it, vi } from 'vitest'
1+
import { describe, expect, it, vi, beforeEach } from 'vitest'
2+
import { parsePackageParams } from '../../../../server/utils/parse-package-params'
3+
import { NPM_MISSING_README_SENTINEL } from '#shared/utils/constants'
24

35
// Mock Nitro globals before importing the module
46
vi.stubGlobal('defineCachedFunction', (fn: Function) => fn)
57
const $fetchMock = vi.fn()
68
vi.stubGlobal('$fetch', $fetchMock)
9+
vi.stubGlobal('parsePackageParams', parsePackageParams)
710

8-
const { fetchReadmeFromJsdelivr, isStandardReadme } =
11+
const fetchNpmPackageMock = vi.fn()
12+
vi.stubGlobal('fetchNpmPackage', fetchNpmPackageMock)
13+
14+
const parseRepositoryInfoMock = vi.fn()
15+
vi.stubGlobal('parseRepositoryInfo', parseRepositoryInfoMock)
16+
17+
const { fetchReadmeFromJsdelivr, isStandardReadme, resolvePackageReadmeSource } =
918
await import('../../../../server/utils/readme-loaders')
1019

1120
describe('isStandardReadme', () => {
@@ -43,20 +52,6 @@ describe('fetchReadmeFromJsdelivr', () => {
4352
expect(fetchMock).toHaveBeenCalledWith('https://cdn.jsdelivr.net/npm/some-pkg/README.md')
4453
})
4554

46-
it('tries next filename when response is not ok', async () => {
47-
const content = '# Fallback'
48-
const fetchMock = vi
49-
.fn()
50-
.mockResolvedValueOnce({ ok: false })
51-
.mockResolvedValueOnce({ ok: true, text: async () => content })
52-
vi.stubGlobal('fetch', fetchMock)
53-
54-
const result = await fetchReadmeFromJsdelivr('pkg', ['README.md', 'readme.md'])
55-
56-
expect(result).toBe(content)
57-
expect(fetchMock).toHaveBeenCalledTimes(2)
58-
})
59-
6055
it('includes version in URL when version is passed', async () => {
6156
const fetchMock = vi.fn().mockResolvedValue({
6257
ok: true,
@@ -79,3 +74,165 @@ describe('fetchReadmeFromJsdelivr', () => {
7974
expect(fetchMock).toHaveBeenCalledTimes(2)
8075
})
8176
})
77+
78+
describe('resolvePackageReadmeSource', () => {
79+
beforeEach(() => {
80+
fetchNpmPackageMock.mockReset()
81+
parseRepositoryInfoMock.mockReset()
82+
})
83+
84+
it('returns markdown and repoInfo when package has valid npm readme (latest)', async () => {
85+
const markdown = '# Hello'
86+
fetchNpmPackageMock.mockResolvedValue({
87+
readme: markdown,
88+
readmeFilename: 'README.md',
89+
repository: { url: 'https://github.com/u/r' },
90+
versions: {},
91+
})
92+
parseRepositoryInfoMock.mockReturnValue({
93+
provider: 'github',
94+
owner: 'u',
95+
repo: 'r',
96+
rawBaseUrl: 'https://raw.githubusercontent.com/u/r/HEAD',
97+
blobBaseUrl: 'https://github.com/u/r/blob/HEAD',
98+
})
99+
100+
const result = await resolvePackageReadmeSource('some-pkg')
101+
102+
expect(result).toMatchObject({
103+
packageName: 'some-pkg',
104+
version: undefined,
105+
markdown,
106+
repoInfo: { provider: 'github', owner: 'u', repo: 'r' },
107+
})
108+
expect(fetchNpmPackageMock).toHaveBeenCalledWith('some-pkg')
109+
})
110+
111+
it('returns markdown from version when packagePath includes version', async () => {
112+
const markdown = '# Version readme'
113+
fetchNpmPackageMock.mockResolvedValue({
114+
readme: 'latest readme',
115+
readmeFilename: 'README.md',
116+
repository: undefined,
117+
versions: {
118+
'1.0.0': { readme: markdown, readmeFilename: 'README.md' },
119+
},
120+
})
121+
parseRepositoryInfoMock.mockReturnValue(undefined)
122+
123+
const result = await resolvePackageReadmeSource('some-pkg/v/1.0.0')
124+
125+
expect(result).toMatchObject({
126+
packageName: 'some-pkg',
127+
version: '1.0.0',
128+
markdown,
129+
})
130+
})
131+
132+
it('falls back to jsdelivr when npm readme is missing sentinel', async () => {
133+
const jsdelivrContent = '# From CDN'
134+
fetchNpmPackageMock.mockResolvedValue({
135+
readme: NPM_MISSING_README_SENTINEL,
136+
readmeFilename: 'README.md',
137+
repository: undefined,
138+
versions: {},
139+
})
140+
parseRepositoryInfoMock.mockReturnValue(undefined)
141+
const fetchMock = vi.fn().mockResolvedValue({
142+
ok: true,
143+
text: async () => jsdelivrContent,
144+
})
145+
vi.stubGlobal('fetch', fetchMock)
146+
147+
const result = await resolvePackageReadmeSource('pkg')
148+
149+
expect(result).toMatchObject({
150+
packageName: 'pkg',
151+
markdown: jsdelivrContent,
152+
repoInfo: undefined,
153+
})
154+
expect(fetchMock).toHaveBeenCalled()
155+
})
156+
157+
it('falls back to jsdelivr when readmeFilename is not standard', async () => {
158+
const jsdelivrContent = '# From CDN'
159+
fetchNpmPackageMock.mockResolvedValue({
160+
readme: 'content',
161+
readmeFilename: 'DOCS.md',
162+
repository: undefined,
163+
versions: {},
164+
})
165+
parseRepositoryInfoMock.mockReturnValue(undefined)
166+
const fetchMock = vi.fn().mockResolvedValue({
167+
ok: true,
168+
text: async () => jsdelivrContent,
169+
})
170+
vi.stubGlobal('fetch', fetchMock)
171+
172+
const result = await resolvePackageReadmeSource('pkg')
173+
174+
expect(result).toMatchObject({ markdown: jsdelivrContent })
175+
})
176+
177+
it('returns undefined markdown when no content and jsdelivr fails', async () => {
178+
fetchNpmPackageMock.mockResolvedValue({
179+
readme: undefined,
180+
readmeFilename: undefined,
181+
repository: undefined,
182+
versions: {},
183+
})
184+
parseRepositoryInfoMock.mockReturnValue(undefined)
185+
const fetchMock = vi.fn().mockResolvedValue({ ok: false })
186+
vi.stubGlobal('fetch', fetchMock)
187+
188+
const result = await resolvePackageReadmeSource('pkg')
189+
190+
expect(result).toMatchObject({
191+
packageName: 'pkg',
192+
version: undefined,
193+
markdown: undefined,
194+
repoInfo: undefined,
195+
})
196+
})
197+
198+
it('returns undefined markdown when content is NPM_MISSING_README_SENTINEL and jsdelivr fails', async () => {
199+
fetchNpmPackageMock.mockResolvedValue({
200+
readme: NPM_MISSING_README_SENTINEL,
201+
readmeFilename: 'README.md',
202+
repository: undefined,
203+
versions: {},
204+
})
205+
const fetchMock = vi.fn().mockResolvedValue({ ok: false })
206+
vi.stubGlobal('fetch', fetchMock)
207+
208+
const result = await resolvePackageReadmeSource('pkg')
209+
210+
expect(result).toMatchObject({
211+
packageName: 'pkg',
212+
markdown: undefined,
213+
repoInfo: undefined,
214+
})
215+
})
216+
217+
it('uses package repository for repoInfo when markdown is present', async () => {
218+
fetchNpmPackageMock.mockResolvedValue({
219+
readme: '# Hi',
220+
readmeFilename: 'README.md',
221+
repository: { url: 'https://github.com/a/b' },
222+
versions: {},
223+
})
224+
const repoInfo = {
225+
provider: 'github' as const,
226+
owner: 'a',
227+
repo: 'b',
228+
rawBaseUrl: 'https://raw.githubusercontent.com/a/b/HEAD',
229+
blobBaseUrl: 'https://github.com/a/b/blob/HEAD',
230+
}
231+
parseRepositoryInfoMock.mockReturnValue(repoInfo)
232+
233+
const result = await resolvePackageReadmeSource('pkg')
234+
235+
expect(result?.repoInfo).toEqual(repoInfo)
236+
expect(parseRepositoryInfoMock).toHaveBeenCalledWith({ url: 'https://github.com/a/b' })
237+
})
238+
})

0 commit comments

Comments
 (0)