@vltpkg/vsr 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +6 -2
- package/test/README.md +0 -91
- package/test/access.test.js +0 -760
- package/test/cloudflare-waituntil.test.js +0 -141
- package/test/db.test.js +0 -447
- package/test/dist-tag.test.js +0 -415
- package/test/e2e.test.js +0 -904
- package/test/hono-context.test.js +0 -250
- package/test/integrity-validation.test.js +0 -183
- package/test/json-response.test.js +0 -76
- package/test/manifest-slimming.test.js +0 -449
- package/test/packument-consistency.test.js +0 -351
- package/test/packument-version-range.test.js +0 -144
- package/test/performance.test.js +0 -162
- package/test/route-with-waituntil.test.js +0 -298
- package/test/run-tests.js +0 -151
- package/test/setup-cache-tests.js +0 -190
- package/test/setup.js +0 -64
- package/test/stale-while-revalidate.test.js +0 -273
- package/test/static-assets.test.js +0 -85
- package/test/upstream-routing.test.js +0 -86
- package/test/utils/test-helpers.js +0 -84
- package/test/waituntil-correct.test.js +0 -208
- package/test/waituntil-demo.test.js +0 -138
- package/test/waituntil-readme.md +0 -113
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { getPackagePackument } from '../src/routes/packages.ts'
|
|
3
|
-
|
|
4
|
-
// Mock config
|
|
5
|
-
vi.mock('../../config.js', () => ({
|
|
6
|
-
DOMAIN: 'https://registry.example.com',
|
|
7
|
-
PROXY: true,
|
|
8
|
-
PROXY_URL: 'https://registry.npmjs.org'
|
|
9
|
-
}))
|
|
10
|
-
|
|
11
|
-
// Mock slimManifest function
|
|
12
|
-
vi.mock('../src/utils/packages.js', () => ({
|
|
13
|
-
slimManifest: (manifest) => {
|
|
14
|
-
// Simple implementation to use in tests
|
|
15
|
-
if (!manifest) return {}
|
|
16
|
-
|
|
17
|
-
const parsed = typeof manifest === 'string' ? JSON.parse(manifest) : manifest
|
|
18
|
-
|
|
19
|
-
// Create a simplified version with only essential fields
|
|
20
|
-
const slimmed = {
|
|
21
|
-
name: parsed.name,
|
|
22
|
-
version: parsed.version,
|
|
23
|
-
description: parsed.description,
|
|
24
|
-
dependencies: parsed.dependencies || {},
|
|
25
|
-
peerDependencies: parsed.peerDependencies || {},
|
|
26
|
-
peerDependenciesMeta: parsed.peerDependenciesMeta || {},
|
|
27
|
-
dist: {
|
|
28
|
-
...(parsed.dist || {}),
|
|
29
|
-
tarball: parsed.dist?.tarball || ''
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Remove undefined values
|
|
34
|
-
Object.keys(slimmed).forEach(key => {
|
|
35
|
-
if (key !== 'dist' && slimmed[key] === undefined) {
|
|
36
|
-
delete slimmed[key]
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
return slimmed
|
|
41
|
-
},
|
|
42
|
-
createVersion: ({ pkg, version, manifest }) => manifest
|
|
43
|
-
}))
|
|
44
|
-
|
|
45
|
-
describe('Packument Response Format', () => {
|
|
46
|
-
// Set up mock data and context
|
|
47
|
-
const setupTest = () => {
|
|
48
|
-
// Mock package data
|
|
49
|
-
const mockPublishedPackage = {
|
|
50
|
-
name: 'local-package',
|
|
51
|
-
tags: { latest: '1.0.0', beta: '1.1.0-beta.1' },
|
|
52
|
-
lastUpdated: '2023-01-01T00:00:00.000Z'
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Mock version data with JSON strings
|
|
56
|
-
const mockVersions = [
|
|
57
|
-
{
|
|
58
|
-
spec: 'local-package@1.0.0',
|
|
59
|
-
version: '1.0.0',
|
|
60
|
-
manifest: JSON.stringify({
|
|
61
|
-
name: 'local-package',
|
|
62
|
-
version: '1.0.0',
|
|
63
|
-
description: 'A locally published package',
|
|
64
|
-
dependencies: { 'some-dep': '^1.0.0' },
|
|
65
|
-
_id: 'local-package@1.0.0',
|
|
66
|
-
_npmUser: { name: 'testuser' },
|
|
67
|
-
readme: 'Very long readme content...',
|
|
68
|
-
dist: {
|
|
69
|
-
shasum: '1234567890abcdef',
|
|
70
|
-
integrity: 'sha512-abcdefghijklmnopqrstuvwxyz0123456789',
|
|
71
|
-
tarball: 'https://registry.example.com/local-package/-/local-package-1.0.0.tgz'
|
|
72
|
-
}
|
|
73
|
-
}),
|
|
74
|
-
published_at: '2023-01-01T00:00:00.000Z'
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
spec: 'local-package@1.1.0-beta.1',
|
|
78
|
-
version: '1.1.0-beta.1',
|
|
79
|
-
manifest: JSON.stringify({
|
|
80
|
-
name: 'local-package',
|
|
81
|
-
version: '1.1.0-beta.1',
|
|
82
|
-
description: 'A locally published package (beta)',
|
|
83
|
-
dependencies: {
|
|
84
|
-
'some-dep': '^1.0.0',
|
|
85
|
-
'another-dep': '^2.0.0'
|
|
86
|
-
},
|
|
87
|
-
_id: 'local-package@1.1.0-beta.1',
|
|
88
|
-
_npmUser: { name: 'testuser' },
|
|
89
|
-
readme: 'Very long readme content for beta...',
|
|
90
|
-
dist: {
|
|
91
|
-
shasum: '0987654321fedcba',
|
|
92
|
-
integrity: 'sha512-zyxwvutsrqponmlkjihgfedcba0987654321',
|
|
93
|
-
tarball: 'https://registry.example.com/local-package/-/local-package-1.1.0-beta.1.tgz'
|
|
94
|
-
}
|
|
95
|
-
}),
|
|
96
|
-
published_at: '2023-01-15T00:00:00.000Z'
|
|
97
|
-
}
|
|
98
|
-
]
|
|
99
|
-
|
|
100
|
-
// Set up mock context
|
|
101
|
-
const mockContext = {
|
|
102
|
-
req: {
|
|
103
|
-
param: vi.fn((name) => {
|
|
104
|
-
if (name === 'pkg') {
|
|
105
|
-
return 'local-package'
|
|
106
|
-
}
|
|
107
|
-
return undefined
|
|
108
|
-
}),
|
|
109
|
-
query: vi.fn((name) => {
|
|
110
|
-
return null; // Return null for any query param
|
|
111
|
-
}),
|
|
112
|
-
url: 'https://registry.example.com/local-package'
|
|
113
|
-
},
|
|
114
|
-
db: {
|
|
115
|
-
getPackage: vi.fn(async (name) => {
|
|
116
|
-
if (name === 'local-package') {
|
|
117
|
-
return { ...mockPublishedPackage }
|
|
118
|
-
}
|
|
119
|
-
return null
|
|
120
|
-
}),
|
|
121
|
-
getVersionsByPackage: vi.fn(async (name) => {
|
|
122
|
-
if (name === 'local-package') {
|
|
123
|
-
return [...mockVersions]
|
|
124
|
-
}
|
|
125
|
-
return []
|
|
126
|
-
}),
|
|
127
|
-
getVersion: vi.fn(async (spec) => {
|
|
128
|
-
return mockVersions.find(v => v.spec === spec)
|
|
129
|
-
}),
|
|
130
|
-
upsertPackage: vi.fn(async () => true),
|
|
131
|
-
upsertVersion: vi.fn(async () => true)
|
|
132
|
-
},
|
|
133
|
-
json: vi.fn((data, status = 200) => ({ body: data, status })),
|
|
134
|
-
header: vi.fn(),
|
|
135
|
-
executionCtx: { waitUntil: vi.fn() },
|
|
136
|
-
env: {}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Mock upstream data
|
|
140
|
-
const mockUpstreamData = {
|
|
141
|
-
name: 'proxied-package',
|
|
142
|
-
_id: 'proxied-package',
|
|
143
|
-
_rev: '123-abc',
|
|
144
|
-
_attachments: {},
|
|
145
|
-
_npmUser: { name: 'upstream-user' },
|
|
146
|
-
maintainers: [{ name: 'upstream-user', email: 'user@example.com' }],
|
|
147
|
-
'dist-tags': { latest: '2.0.0', next: '2.1.0-rc.1' },
|
|
148
|
-
versions: {
|
|
149
|
-
'2.0.0': {
|
|
150
|
-
name: 'proxied-package',
|
|
151
|
-
version: '2.0.0',
|
|
152
|
-
description: 'A proxied package',
|
|
153
|
-
dependencies: { 'dep1': '^1.0.0' },
|
|
154
|
-
_id: 'proxied-package@2.0.0',
|
|
155
|
-
_npmUser: { name: 'upstream-user' },
|
|
156
|
-
readme: 'Very long readme content...',
|
|
157
|
-
dist: {
|
|
158
|
-
shasum: 'abcdef1234567890',
|
|
159
|
-
integrity: 'sha512-abcdefghijklmnopqrstuvwxyz0123456789',
|
|
160
|
-
tarball: 'https://registry.npmjs.org/proxied-package/-/proxied-package-2.0.0.tgz'
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
'2.1.0-rc.1': {
|
|
164
|
-
name: 'proxied-package',
|
|
165
|
-
version: '2.1.0-rc.1',
|
|
166
|
-
description: 'A proxied package (RC)',
|
|
167
|
-
dependencies: { 'dep1': '^1.0.0', 'dep2': '^3.0.0' },
|
|
168
|
-
_id: 'proxied-package@2.1.0-rc.1',
|
|
169
|
-
_npmUser: { name: 'upstream-user' },
|
|
170
|
-
readme: 'Very long readme content for RC...',
|
|
171
|
-
dist: {
|
|
172
|
-
shasum: 'fedcba0987654321',
|
|
173
|
-
integrity: 'sha512-zyxwvutsrqponmlkjihgfedcba0987654321',
|
|
174
|
-
tarball: 'https://registry.npmjs.org/proxied-package/-/proxied-package-2.1.0-rc.1.tgz'
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
time: {
|
|
179
|
-
modified: '2023-02-01T00:00:00.000Z',
|
|
180
|
-
created: '2023-01-01T00:00:00.000Z',
|
|
181
|
-
'2.0.0': '2023-01-15T00:00:00.000Z',
|
|
182
|
-
'2.1.0-rc.1': '2023-02-01T00:00:00.000Z'
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Mock fetch for proxied package
|
|
187
|
-
global.fetch = vi.fn(async (url) => {
|
|
188
|
-
if (url.includes('proxied-package')) {
|
|
189
|
-
return {
|
|
190
|
-
ok: true,
|
|
191
|
-
status: 200,
|
|
192
|
-
json: async () => ({ ...mockUpstreamData })
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
ok: false,
|
|
197
|
-
status: 404,
|
|
198
|
-
json: async () => ({ error: 'Not found' })
|
|
199
|
-
}
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
mockContext,
|
|
204
|
-
mockUpstreamData,
|
|
205
|
-
mockPublishedPackage,
|
|
206
|
-
mockVersions
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
beforeEach(() => {
|
|
211
|
-
vi.resetAllMocks()
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
it('should return consistent packument for local packages with only required fields', async () => {
|
|
215
|
-
const { mockContext } = setupTest()
|
|
216
|
-
|
|
217
|
-
await getPackagePackument(mockContext)
|
|
218
|
-
|
|
219
|
-
expect(mockContext.json).toHaveBeenCalled()
|
|
220
|
-
const responseData = mockContext.json.mock.calls[0][0]
|
|
221
|
-
|
|
222
|
-
// Verify structure
|
|
223
|
-
expect(responseData).toHaveProperty('name', 'local-package')
|
|
224
|
-
expect(responseData).toHaveProperty('dist-tags')
|
|
225
|
-
expect(responseData).toHaveProperty('versions')
|
|
226
|
-
expect(responseData).toHaveProperty('time')
|
|
227
|
-
|
|
228
|
-
// Verify dist-tags
|
|
229
|
-
expect(responseData['dist-tags']).toEqual({
|
|
230
|
-
latest: '1.0.0',
|
|
231
|
-
beta: '1.1.0-beta.1'
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
// Verify versions exist
|
|
235
|
-
expect(responseData.versions).toHaveProperty('1.0.0')
|
|
236
|
-
expect(responseData.versions).toHaveProperty('1.1.0-beta.1')
|
|
237
|
-
|
|
238
|
-
// Check slimming of sensitive data
|
|
239
|
-
const version = responseData.versions['1.0.0']
|
|
240
|
-
expect(version).toBeDefined()
|
|
241
|
-
expect(version).not.toHaveProperty('_id')
|
|
242
|
-
expect(version).not.toHaveProperty('_npmUser')
|
|
243
|
-
expect(version).not.toHaveProperty('readme')
|
|
244
|
-
|
|
245
|
-
// Verify contains required fields
|
|
246
|
-
expect(version).toHaveProperty('name', 'local-package')
|
|
247
|
-
expect(version).toHaveProperty('version', '1.0.0')
|
|
248
|
-
expect(version).toHaveProperty('dist')
|
|
249
|
-
|
|
250
|
-
// Verify status
|
|
251
|
-
expect(mockContext.json.mock.calls[0][1]).toBe(200)
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('should return consistent packument for proxied packages with only required fields', async () => {
|
|
255
|
-
const { mockContext } = setupTest()
|
|
256
|
-
|
|
257
|
-
// Change request to fetch proxied package
|
|
258
|
-
mockContext.req.param = vi.fn((name) => {
|
|
259
|
-
if (name === 'pkg') {
|
|
260
|
-
return 'proxied-package'
|
|
261
|
-
}
|
|
262
|
-
return undefined
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
// Capture dist-tags for verification
|
|
266
|
-
let capturedTags = null
|
|
267
|
-
mockContext.db.upsertPackage = vi.fn(async (name, tags) => {
|
|
268
|
-
capturedTags = tags
|
|
269
|
-
return true
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
await getPackagePackument(mockContext)
|
|
273
|
-
|
|
274
|
-
// Verify response
|
|
275
|
-
expect(mockContext.json).toHaveBeenCalled()
|
|
276
|
-
const responseData = mockContext.json.mock.calls[0][0]
|
|
277
|
-
|
|
278
|
-
// Verify structure
|
|
279
|
-
expect(responseData).toHaveProperty('name', 'proxied-package')
|
|
280
|
-
expect(responseData).toHaveProperty('dist-tags')
|
|
281
|
-
expect(responseData).toHaveProperty('versions')
|
|
282
|
-
expect(responseData).toHaveProperty('time')
|
|
283
|
-
|
|
284
|
-
// Check that tags were properly stored
|
|
285
|
-
expect(capturedTags).toEqual({
|
|
286
|
-
latest: '2.0.0',
|
|
287
|
-
next: '2.1.0-rc.1'
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
// Verify no extra fields
|
|
291
|
-
expect(responseData).not.toHaveProperty('_id')
|
|
292
|
-
expect(responseData).not.toHaveProperty('_rev')
|
|
293
|
-
expect(responseData).not.toHaveProperty('_attachments')
|
|
294
|
-
|
|
295
|
-
// Verify versions exist
|
|
296
|
-
expect(Object.keys(responseData.versions)).toContain('2.0.0')
|
|
297
|
-
expect(Object.keys(responseData.versions)).toContain('2.1.0-rc.1')
|
|
298
|
-
|
|
299
|
-
// Check version format
|
|
300
|
-
const version = responseData.versions['2.0.0']
|
|
301
|
-
expect(version).toBeDefined()
|
|
302
|
-
expect(version).toHaveProperty('name', 'proxied-package')
|
|
303
|
-
expect(version).toHaveProperty('version', '2.0.0')
|
|
304
|
-
expect(version).not.toHaveProperty('_id')
|
|
305
|
-
expect(version).not.toHaveProperty('_npmUser')
|
|
306
|
-
expect(version).not.toHaveProperty('readme')
|
|
307
|
-
|
|
308
|
-
// Verify status
|
|
309
|
-
expect(mockContext.json.mock.calls[0][1]).toBe(200)
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
it('should handle background refresh while maintaining consistent response format', async () => {
|
|
313
|
-
const { mockContext } = setupTest()
|
|
314
|
-
|
|
315
|
-
// Setup stale timestamp
|
|
316
|
-
const oldDate = new Date()
|
|
317
|
-
oldDate.setDate(oldDate.getDate() - 10)
|
|
318
|
-
|
|
319
|
-
// Mock stale package data
|
|
320
|
-
mockContext.db.getPackage = vi.fn(async (name) => {
|
|
321
|
-
if (name === 'local-package') {
|
|
322
|
-
return {
|
|
323
|
-
name: 'local-package',
|
|
324
|
-
tags: { latest: '1.0.0', beta: '1.1.0-beta.1' },
|
|
325
|
-
lastUpdated: oldDate.toISOString()
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return null
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
await getPackagePackument(mockContext)
|
|
332
|
-
|
|
333
|
-
// Verify background refresh was triggered
|
|
334
|
-
expect(mockContext.executionCtx.waitUntil).toHaveBeenCalled()
|
|
335
|
-
|
|
336
|
-
// Verify response
|
|
337
|
-
expect(mockContext.json).toHaveBeenCalled()
|
|
338
|
-
const responseData = mockContext.json.mock.calls[0][0]
|
|
339
|
-
|
|
340
|
-
// Verify structure
|
|
341
|
-
expect(responseData).toEqual(expect.objectContaining({
|
|
342
|
-
name: 'local-package',
|
|
343
|
-
'dist-tags': expect.any(Object),
|
|
344
|
-
versions: expect.any(Object),
|
|
345
|
-
time: expect.any(Object)
|
|
346
|
-
}))
|
|
347
|
-
|
|
348
|
-
// Verify status
|
|
349
|
-
expect(mockContext.json.mock.calls[0][1]).toBe(200)
|
|
350
|
-
})
|
|
351
|
-
})
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
import * as semver from 'semver'
|
|
3
|
-
|
|
4
|
-
// Mock semver to use actual implementation
|
|
5
|
-
vi.mock('semver', async () => {
|
|
6
|
-
const actual = await vi.importActual('semver')
|
|
7
|
-
return {
|
|
8
|
-
...actual
|
|
9
|
-
}
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
// Mock config
|
|
13
|
-
vi.mock('../../config.js', () => ({
|
|
14
|
-
DOMAIN: 'https://registry.example.com',
|
|
15
|
-
PROXY: false // Disable proxy for these tests
|
|
16
|
-
}))
|
|
17
|
-
|
|
18
|
-
describe('Packument Version Range Filtering', () => {
|
|
19
|
-
// Test the versionRange filtering functionality directly
|
|
20
|
-
describe('Core semver filtering behavior', () => {
|
|
21
|
-
|
|
22
|
-
// Create a realistic set of package versions
|
|
23
|
-
const versions = [
|
|
24
|
-
'1.0.0', '1.0.1', '1.1.0', '1.2.0', '1.2.3', // Major 1
|
|
25
|
-
'2.0.0', '2.0.1', '2.1.0', // Major 2
|
|
26
|
-
'3.0.0-beta.1', '3.0.0-beta.2', // Pre-release versions
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
// Function to simulate the filtering logic from our implementation
|
|
30
|
-
const filterVersionsByRange = (versions, range) => {
|
|
31
|
-
if (!semver.validRange(range)) {
|
|
32
|
-
throw new Error(`Invalid semver range: ${range}`)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return versions.filter(version => semver.satisfies(version, range))
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
it('should validate semver ranges correctly', () => {
|
|
39
|
-
// Valid ranges
|
|
40
|
-
expect(semver.validRange('1.x')).toBeTruthy()
|
|
41
|
-
expect(semver.validRange('^2.0.0')).toBeTruthy()
|
|
42
|
-
expect(semver.validRange('~2.0.0')).toBeTruthy()
|
|
43
|
-
expect(semver.validRange('>=1.2.0 <2.1.0')).toBeTruthy()
|
|
44
|
-
expect(semver.validRange('^3.0.0-0')).toBeTruthy()
|
|
45
|
-
|
|
46
|
-
// Invalid range
|
|
47
|
-
expect(semver.validRange('not-a-valid-range')).toBeNull()
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should filter by major version (1.x)', () => {
|
|
51
|
-
const range = '1.x'
|
|
52
|
-
const filtered = filterVersionsByRange(versions, range)
|
|
53
|
-
|
|
54
|
-
// Should only include major 1 versions
|
|
55
|
-
const expected = ['1.0.0', '1.0.1', '1.1.0', '1.2.0', '1.2.3']
|
|
56
|
-
expect(filtered).toEqual(expected)
|
|
57
|
-
expect(filtered.length).toBe(5)
|
|
58
|
-
|
|
59
|
-
// Shouldn't include major 2 or 3
|
|
60
|
-
expect(filtered).not.toContain('2.0.0')
|
|
61
|
-
expect(filtered).not.toContain('3.0.0-beta.1')
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('should filter with caret range (^2.0.0)', () => {
|
|
65
|
-
const range = '^2.0.0'
|
|
66
|
-
const filtered = filterVersionsByRange(versions, range)
|
|
67
|
-
|
|
68
|
-
// Should include all 2.x versions
|
|
69
|
-
const expected = ['2.0.0', '2.0.1', '2.1.0']
|
|
70
|
-
expect(filtered).toEqual(expected)
|
|
71
|
-
expect(filtered.length).toBe(3)
|
|
72
|
-
|
|
73
|
-
// Shouldn't include major 1 or 3
|
|
74
|
-
expect(filtered).not.toContain('1.2.3')
|
|
75
|
-
expect(filtered).not.toContain('3.0.0-beta.1')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('should filter with tilde range (~2.0.0)', () => {
|
|
79
|
-
const range = '~2.0.0'
|
|
80
|
-
const filtered = filterVersionsByRange(versions, range)
|
|
81
|
-
|
|
82
|
-
// Should only include patch versions of 2.0
|
|
83
|
-
const expected = ['2.0.0', '2.0.1']
|
|
84
|
-
expect(filtered).toEqual(expected)
|
|
85
|
-
expect(filtered.length).toBe(2)
|
|
86
|
-
|
|
87
|
-
// Shouldn't include minor versions
|
|
88
|
-
expect(filtered).not.toContain('2.1.0')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('should filter with complex range (>=1.2.0 <2.1.0)', () => {
|
|
92
|
-
const range = '>=1.2.0 <2.1.0'
|
|
93
|
-
const filtered = filterVersionsByRange(versions, range)
|
|
94
|
-
|
|
95
|
-
// Should include specified range
|
|
96
|
-
const expected = ['1.2.0', '1.2.3', '2.0.0', '2.0.1']
|
|
97
|
-
expect(filtered).toEqual(expected)
|
|
98
|
-
expect(filtered.length).toBe(4)
|
|
99
|
-
|
|
100
|
-
// Verify boundaries are respected
|
|
101
|
-
expect(filtered).not.toContain('1.1.0')
|
|
102
|
-
expect(filtered).not.toContain('2.1.0')
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('should handle pre-release versions when explicitly included (^3.0.0-0)', () => {
|
|
106
|
-
const range = '^3.0.0-0'
|
|
107
|
-
const filtered = filterVersionsByRange(versions, range)
|
|
108
|
-
|
|
109
|
-
// Should include beta versions
|
|
110
|
-
const expected = ['3.0.0-beta.1', '3.0.0-beta.2']
|
|
111
|
-
expect(filtered).toEqual(expected)
|
|
112
|
-
expect(filtered.length).toBe(2)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should reject invalid semver ranges', () => {
|
|
116
|
-
const range = 'not-a-valid-range'
|
|
117
|
-
expect(() => filterVersionsByRange(versions, range)).toThrow('Invalid semver range')
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
// Test the API integration with minimal mocking
|
|
122
|
-
describe('API implementation integration', () => {
|
|
123
|
-
it('should correctly integrate with the API', () => {
|
|
124
|
-
// Verify that the actual API implementation would correctly:
|
|
125
|
-
// 1. Extract the versionRange query parameter
|
|
126
|
-
// 2. Validate it using semver.validRange
|
|
127
|
-
// 3. Filter versions using semver.satisfies
|
|
128
|
-
|
|
129
|
-
// Instead of trying to mock the entire system, we're just
|
|
130
|
-
// asserting here that the core semver functionality works
|
|
131
|
-
// as expected when integrated with our API filtering logic
|
|
132
|
-
|
|
133
|
-
const validRange = semver.validRange('^1.0.0')
|
|
134
|
-
expect(validRange).toBeTruthy()
|
|
135
|
-
|
|
136
|
-
const version = '1.2.3'
|
|
137
|
-
const matchesRange = semver.satisfies(version, '^1.0.0')
|
|
138
|
-
expect(matchesRange).toBe(true)
|
|
139
|
-
|
|
140
|
-
const doesntMatch = semver.satisfies('2.0.0', '^1.0.0')
|
|
141
|
-
expect(doesntMatch).toBe(false)
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
|
-
})
|
package/test/performance.test.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
-
import { unstable_dev } from 'wrangler'
|
|
3
|
-
|
|
4
|
-
describe('Performance Tests', () => {
|
|
5
|
-
let worker
|
|
6
|
-
|
|
7
|
-
beforeAll(async () => {
|
|
8
|
-
worker = await unstable_dev('src/index.js', {
|
|
9
|
-
experimental: { disableExperimentalWarning: true },
|
|
10
|
-
local: true,
|
|
11
|
-
port: 1338, // Use different port to avoid conflicts
|
|
12
|
-
})
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
afterAll(async () => {
|
|
16
|
-
await worker.stop()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
async function measureRequestTime(url, expectJson = true) {
|
|
20
|
-
const start = Date.now()
|
|
21
|
-
const response = await fetch(url)
|
|
22
|
-
const end = Date.now()
|
|
23
|
-
const duration = end - start
|
|
24
|
-
|
|
25
|
-
let data = null
|
|
26
|
-
if (response.ok && expectJson) {
|
|
27
|
-
try {
|
|
28
|
-
data = await response.json()
|
|
29
|
-
} catch (e) {
|
|
30
|
-
// Handle non-JSON responses (like tarballs)
|
|
31
|
-
data = null
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
duration,
|
|
37
|
-
ok: response.ok,
|
|
38
|
-
status: response.status,
|
|
39
|
-
data
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
it('should be faster than npm registry for packument requests', async () => {
|
|
44
|
-
const testPackage = 'lodash'
|
|
45
|
-
|
|
46
|
-
// Test npm registry directly
|
|
47
|
-
const npmResult = await measureRequestTime(`https://registry.npmjs.org/${testPackage}`)
|
|
48
|
-
console.log(`NPM registry time: ${npmResult.duration}ms`)
|
|
49
|
-
|
|
50
|
-
// Test our registry (first request - cache miss)
|
|
51
|
-
const ourFirstResult = await measureRequestTime(`http://localhost:1338/npm/${testPackage}`)
|
|
52
|
-
console.log(`Our registry (first): ${ourFirstResult.duration}ms`)
|
|
53
|
-
|
|
54
|
-
// Test our registry (second request - should be cached)
|
|
55
|
-
const ourSecondResult = await measureRequestTime(`http://localhost:1338/npm/${testPackage}`)
|
|
56
|
-
console.log(`Our registry (cached): ${ourSecondResult.duration}ms`)
|
|
57
|
-
|
|
58
|
-
expect(npmResult.ok).toBe(true)
|
|
59
|
-
expect(ourFirstResult.ok).toBe(true)
|
|
60
|
-
expect(ourSecondResult.ok).toBe(true)
|
|
61
|
-
|
|
62
|
-
// Second request should be faster than first (due to caching)
|
|
63
|
-
expect(ourSecondResult.duration).toBeLessThan(ourFirstResult.duration)
|
|
64
|
-
|
|
65
|
-
// Cached request should be faster than npm (relaxed expectation)
|
|
66
|
-
expect(ourSecondResult.duration).toBeLessThan(npmResult.duration * 2) // Allow up to 2x npm time
|
|
67
|
-
}, 30000)
|
|
68
|
-
|
|
69
|
-
it('should cache tarball requests effectively', async () => {
|
|
70
|
-
const testPackage = 'lodash'
|
|
71
|
-
const testVersion = '4.17.21'
|
|
72
|
-
const tarballUrl = `http://localhost:1338/npm/${testPackage}/-/${testPackage}-${testVersion}.tgz`
|
|
73
|
-
|
|
74
|
-
// First tarball request (don't expect JSON)
|
|
75
|
-
const firstRequest = await measureRequestTime(tarballUrl, false)
|
|
76
|
-
console.log(`Tarball (first): ${firstRequest.duration}ms`)
|
|
77
|
-
|
|
78
|
-
// Second tarball request (should be cached)
|
|
79
|
-
const secondRequest = await measureRequestTime(tarballUrl, false)
|
|
80
|
-
console.log(`Tarball (cached): ${secondRequest.duration}ms`)
|
|
81
|
-
|
|
82
|
-
expect(firstRequest.ok).toBe(true)
|
|
83
|
-
expect(secondRequest.ok).toBe(true)
|
|
84
|
-
|
|
85
|
-
// Second request should be reasonably fast (allow for network variance)
|
|
86
|
-
expect(secondRequest.duration).toBeLessThan(firstRequest.duration * 3) // Allow more variance for small requests
|
|
87
|
-
}, 30000)
|
|
88
|
-
|
|
89
|
-
it('should handle manifest requests efficiently', async () => {
|
|
90
|
-
const testPackage = 'express'
|
|
91
|
-
const testVersion = '4.18.2'
|
|
92
|
-
const manifestUrl = `http://localhost:1338/npm/${testPackage}/${testVersion}`
|
|
93
|
-
|
|
94
|
-
// First manifest request
|
|
95
|
-
const firstRequest = await measureRequestTime(manifestUrl)
|
|
96
|
-
console.log(`Manifest (first): ${firstRequest.duration}ms`)
|
|
97
|
-
|
|
98
|
-
// Second manifest request (should be cached)
|
|
99
|
-
const secondRequest = await measureRequestTime(manifestUrl)
|
|
100
|
-
console.log(`Manifest (cached): ${secondRequest.duration}ms`)
|
|
101
|
-
|
|
102
|
-
expect(firstRequest.ok).toBe(true)
|
|
103
|
-
expect(secondRequest.ok).toBe(true)
|
|
104
|
-
|
|
105
|
-
// Verify the manifest has rewritten tarball URLs to our domain
|
|
106
|
-
expect(secondRequest.data.dist.tarball).toContain('localhost')
|
|
107
|
-
expect(secondRequest.data.dist.tarball).toContain(testPackage)
|
|
108
|
-
|
|
109
|
-
// Second request should be faster or at least not much slower
|
|
110
|
-
expect(secondRequest.duration).toBeLessThan(firstRequest.duration * 1.5) // Allow some variance
|
|
111
|
-
}, 30000)
|
|
112
|
-
|
|
113
|
-
it('should demonstrate racing cache performance', async () => {
|
|
114
|
-
const testPackages = ['react', 'vue', 'angular']
|
|
115
|
-
const results = []
|
|
116
|
-
|
|
117
|
-
for (const pkg of testPackages) {
|
|
118
|
-
// Measure cold request (no cache)
|
|
119
|
-
const coldResult = await measureRequestTime(`http://localhost:1338/npm/${pkg}`)
|
|
120
|
-
|
|
121
|
-
// Measure warm request (potentially cached)
|
|
122
|
-
const warmResult = await measureRequestTime(`http://localhost:1338/npm/${pkg}`)
|
|
123
|
-
|
|
124
|
-
results.push({
|
|
125
|
-
package: pkg,
|
|
126
|
-
cold: coldResult.duration,
|
|
127
|
-
warm: warmResult.duration,
|
|
128
|
-
improvement: ((coldResult.duration - warmResult.duration) / coldResult.duration * 100).toFixed(1)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
console.log(`${pkg}: Cold ${coldResult.duration}ms, Warm ${warmResult.duration}ms (${results[results.length-1].improvement}% faster)`)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// At least some packages should show improvement (or at least not be much worse)
|
|
135
|
-
const reasonableResults = results.filter(r => parseFloat(r.improvement) > -50) // Allow up to 50% slower due to racing
|
|
136
|
-
expect(reasonableResults.length).toBeGreaterThan(0)
|
|
137
|
-
}, 60000)
|
|
138
|
-
|
|
139
|
-
it('should handle high concurrency efficiently', async () => {
|
|
140
|
-
const testPackage = 'uuid'
|
|
141
|
-
const concurrency = 10
|
|
142
|
-
|
|
143
|
-
// Make concurrent requests
|
|
144
|
-
const promises = Array(concurrency).fill().map((_, i) =>
|
|
145
|
-
measureRequestTime(`http://localhost:1338/npm/${testPackage}?_t=${i}`)
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
const start = Date.now()
|
|
149
|
-
const results = await Promise.all(promises)
|
|
150
|
-
const totalTime = Date.now() - start
|
|
151
|
-
|
|
152
|
-
console.log(`${concurrency} concurrent requests completed in ${totalTime}ms`)
|
|
153
|
-
console.log(`Average per request: ${(totalTime / concurrency).toFixed(1)}ms`)
|
|
154
|
-
|
|
155
|
-
// All requests should succeed
|
|
156
|
-
expect(results.every(r => r.ok)).toBe(true)
|
|
157
|
-
|
|
158
|
-
// Concurrent requests shouldn't be much slower than sequential
|
|
159
|
-
const avgRequestTime = totalTime / concurrency
|
|
160
|
-
expect(avgRequestTime).toBeLessThan(5000) // Should average less than 5 seconds per request
|
|
161
|
-
}, 60000)
|
|
162
|
-
})
|