@vltpkg/vsr 0.0.0-26 โ 0.0.0-28
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/dist/README.md +1 -0
- package/dist/assets/public/favicon.ico +0 -0
- package/dist/assets/public/fonts/courier-bold-italic.ttf +0 -0
- package/dist/assets/public/fonts/courier-bold.ttf +0 -0
- package/dist/assets/public/fonts/courier-italic.ttf +0 -0
- package/dist/assets/public/fonts/courier-regular.ttf +0 -0
- package/dist/assets/public/fonts/geist-mono.ttf +0 -0
- package/dist/assets/public/fonts/inter.ttf +0 -0
- package/dist/assets/public/images/bg.png +0 -0
- package/dist/assets/public/images/clients/logo-bun.png +0 -0
- package/dist/assets/public/images/clients/logo-deno.png +0 -0
- package/dist/assets/public/images/clients/logo-npm.png +0 -0
- package/dist/assets/public/images/clients/logo-pnpm.png +0 -0
- package/dist/assets/public/images/clients/logo-vlt.png +0 -0
- package/dist/assets/public/images/clients/logo-yarn.png +0 -0
- package/dist/assets/public/images/favicon/apple-touch-icon.png +0 -0
- package/dist/assets/public/images/favicon/favicon-96x96.png +0 -0
- package/dist/assets/public/images/favicon/favicon.ico +0 -0
- package/dist/assets/public/images/favicon/favicon.svg +3 -0
- package/dist/assets/public/images/favicon/site.webmanifest +21 -0
- package/dist/assets/public/images/favicon/web-app-manifest-192x192.png +0 -0
- package/dist/assets/public/images/favicon/web-app-manifest-512x512.png +0 -0
- package/dist/assets/public/index.html +70 -0
- package/dist/assets/public/index.js +1300 -0
- package/dist/assets/public/index.js.map +7 -0
- package/dist/assets/public/main.css +1 -0
- package/dist/assets/public/styles/styles.css +231 -0
- package/dist/bin/demo/package.json +6 -0
- package/dist/bin/demo/vlt.json +1 -0
- package/dist/bin/vsr.js +773 -0
- package/dist/index.js +28280 -0
- package/dist/index.js.map +8 -0
- package/package.json +6 -6
- package/scripts/build-bin.js +1 -0
- package/src/bin/vsr.ts +15 -3
- package/scripts/prepack.js +0 -27
- package/test/access.test.ts +0 -705
- package/test/audit.test.ts +0 -828
- package/test/dashboard.test.ts +0 -693
- package/test/dist-tags.test.ts +0 -678
- package/test/manifest.test.ts +0 -436
- package/test/packument.test.ts +0 -530
- package/test/ping.test.ts +0 -41
- package/test/search.test.ts +0 -472
- package/test/setup.ts +0 -130
- package/test/static.test.ts +0 -646
- package/test/tokens.test.ts +0 -389
- package/test/utils/auth.test.ts +0 -214
- package/test/utils/packages.test.ts +0 -235
- package/test/utils/response.test.ts +0 -184
- package/test/whoami.test.ts +0 -119
package/test/search.test.ts
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { env } from 'cloudflare:test'
|
|
3
|
-
import { app } from '../src/index.ts'
|
|
4
|
-
|
|
5
|
-
describe('Search Endpoints', () => {
|
|
6
|
-
describe('Root Registry Search', () => {
|
|
7
|
-
describe('GET /-/search', () => {
|
|
8
|
-
it('should handle basic search requests', async () => {
|
|
9
|
-
const res = await app.request(
|
|
10
|
-
'/-/search?text=lodash',
|
|
11
|
-
{},
|
|
12
|
-
env,
|
|
13
|
-
)
|
|
14
|
-
expect(res.status).toBe(200)
|
|
15
|
-
expect(res.headers.get('content-type')).toContain(
|
|
16
|
-
'application/json',
|
|
17
|
-
)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('should handle search without query parameters', async () => {
|
|
21
|
-
const res = await app.request('/-/search', {}, env)
|
|
22
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
23
|
-
expect(res.headers.get('content-type')).toContain(
|
|
24
|
-
'application/json',
|
|
25
|
-
)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('should handle search with multiple parameters', async () => {
|
|
29
|
-
const res = await app.request(
|
|
30
|
-
'/-/search?text=lodash&size=20&from=0',
|
|
31
|
-
{},
|
|
32
|
-
env,
|
|
33
|
-
)
|
|
34
|
-
expect(res.status).toBe(200)
|
|
35
|
-
expect(res.headers.get('content-type')).toContain(
|
|
36
|
-
'application/json',
|
|
37
|
-
)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('should handle search with quality scoring', async () => {
|
|
41
|
-
const res = await app.request(
|
|
42
|
-
'/-/search?text=lodash&quality=0.8',
|
|
43
|
-
{},
|
|
44
|
-
env,
|
|
45
|
-
)
|
|
46
|
-
expect(res.status).toBe(200)
|
|
47
|
-
expect(res.headers.get('content-type')).toContain(
|
|
48
|
-
'application/json',
|
|
49
|
-
)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('should handle search with popularity scoring', async () => {
|
|
53
|
-
const res = await app.request(
|
|
54
|
-
'/-/search?text=lodash&popularity=0.9',
|
|
55
|
-
{},
|
|
56
|
-
env,
|
|
57
|
-
)
|
|
58
|
-
expect(res.status).toBe(200)
|
|
59
|
-
expect(res.headers.get('content-type')).toContain(
|
|
60
|
-
'application/json',
|
|
61
|
-
)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('should handle search with maintenance scoring', async () => {
|
|
65
|
-
const res = await app.request(
|
|
66
|
-
'/-/search?text=lodash&maintenance=0.7',
|
|
67
|
-
{},
|
|
68
|
-
env,
|
|
69
|
-
)
|
|
70
|
-
expect(res.status).toBe(200)
|
|
71
|
-
expect(res.headers.get('content-type')).toContain(
|
|
72
|
-
'application/json',
|
|
73
|
-
)
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
describe('Search Response Structure', () => {
|
|
78
|
-
it('should return proper JSON structure for search results', async () => {
|
|
79
|
-
const res = await app.request(
|
|
80
|
-
'/-/search?text=lodash',
|
|
81
|
-
{},
|
|
82
|
-
env,
|
|
83
|
-
)
|
|
84
|
-
expect(res.status).toBe(200)
|
|
85
|
-
const data = (await res.json()) as any
|
|
86
|
-
expect(data).toBeDefined()
|
|
87
|
-
// Search results structure would be validated based on npm registry format
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('should handle empty search results', async () => {
|
|
91
|
-
const res = await app.request(
|
|
92
|
-
'/-/search?text=nonexistent-package-12345',
|
|
93
|
-
{},
|
|
94
|
-
env,
|
|
95
|
-
)
|
|
96
|
-
expect(res.status).toBe(200)
|
|
97
|
-
const data = (await res.json()) as any
|
|
98
|
-
expect(data).toBeDefined()
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should include pagination information', async () => {
|
|
102
|
-
const res = await app.request(
|
|
103
|
-
'/-/search?text=lodash&size=10&from=0',
|
|
104
|
-
{},
|
|
105
|
-
env,
|
|
106
|
-
)
|
|
107
|
-
expect(res.status).toBe(200)
|
|
108
|
-
const data = (await res.json()) as any
|
|
109
|
-
expect(data).toBeDefined()
|
|
110
|
-
// Would validate pagination fields based on implementation
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
describe('Search Query Parameters', () => {
|
|
115
|
-
it('should handle URL-encoded search terms', async () => {
|
|
116
|
-
const res = await app.request(
|
|
117
|
-
'/-/search?text=%40types%2Fnode',
|
|
118
|
-
{},
|
|
119
|
-
env,
|
|
120
|
-
)
|
|
121
|
-
expect(res.status).toBe(200)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('should handle special characters in search', async () => {
|
|
125
|
-
const res = await app.request(
|
|
126
|
-
'/-/search?text=package-with-dashes',
|
|
127
|
-
{},
|
|
128
|
-
env,
|
|
129
|
-
)
|
|
130
|
-
expect(res.status).toBe(200)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should handle scoped package searches', async () => {
|
|
134
|
-
const res = await app.request(
|
|
135
|
-
'/-/search?text=@types',
|
|
136
|
-
{},
|
|
137
|
-
env,
|
|
138
|
-
)
|
|
139
|
-
expect(res.status).toBe(200)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('should validate size parameter limits', async () => {
|
|
143
|
-
const res = await app.request(
|
|
144
|
-
'/-/search?text=lodash&size=1000',
|
|
145
|
-
{},
|
|
146
|
-
env,
|
|
147
|
-
)
|
|
148
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should validate from parameter', async () => {
|
|
152
|
-
const res = await app.request(
|
|
153
|
-
'/-/search?text=lodash&from=-1',
|
|
154
|
-
{},
|
|
155
|
-
env,
|
|
156
|
-
)
|
|
157
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
158
|
-
})
|
|
159
|
-
})
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
describe('Upstream Registry Search', () => {
|
|
163
|
-
describe('NPM Registry Search', () => {
|
|
164
|
-
it('should handle npm upstream search', async () => {
|
|
165
|
-
const res = await app.request(
|
|
166
|
-
'/npm/-/search?text=lodash',
|
|
167
|
-
{},
|
|
168
|
-
env,
|
|
169
|
-
)
|
|
170
|
-
expect(res.status).toBe(200)
|
|
171
|
-
expect(res.headers.get('content-type')).toContain(
|
|
172
|
-
'application/json',
|
|
173
|
-
)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should handle npm scoped package search', async () => {
|
|
177
|
-
const res = await app.request(
|
|
178
|
-
'/npm/-/search?text=@types/node',
|
|
179
|
-
{},
|
|
180
|
-
env,
|
|
181
|
-
)
|
|
182
|
-
expect(res.status).toBe(200)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('should handle npm search with filters', async () => {
|
|
186
|
-
const res = await app.request(
|
|
187
|
-
'/npm/-/search?text=lodash&quality=0.8&popularity=0.9',
|
|
188
|
-
{},
|
|
189
|
-
env,
|
|
190
|
-
)
|
|
191
|
-
expect(res.status).toBe(200)
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
describe('JSR Registry Search', () => {
|
|
196
|
-
it('should handle jsr upstream search', async () => {
|
|
197
|
-
const res = await app.request(
|
|
198
|
-
'/jsr/-/search?text=std',
|
|
199
|
-
{},
|
|
200
|
-
env,
|
|
201
|
-
)
|
|
202
|
-
expect(res.status).toBe(200)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should handle jsr scoped package search', async () => {
|
|
206
|
-
const res = await app.request(
|
|
207
|
-
'/jsr/-/search?text=@std/fs',
|
|
208
|
-
{},
|
|
209
|
-
env,
|
|
210
|
-
)
|
|
211
|
-
expect(res.status).toBe(200)
|
|
212
|
-
})
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
describe('Custom Registry Search', () => {
|
|
216
|
-
it('should handle custom upstream search', async () => {
|
|
217
|
-
const res = await app.request(
|
|
218
|
-
'/custom/-/search?text=package',
|
|
219
|
-
{},
|
|
220
|
-
env,
|
|
221
|
-
)
|
|
222
|
-
expect(res.status).toBe(200)
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
it('should handle local upstream search', async () => {
|
|
226
|
-
const res = await app.request(
|
|
227
|
-
'/local/-/search?text=package',
|
|
228
|
-
{},
|
|
229
|
-
env,
|
|
230
|
-
)
|
|
231
|
-
expect(res.status).toBe(200)
|
|
232
|
-
})
|
|
233
|
-
})
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
describe('Legacy Search Redirects', () => {
|
|
237
|
-
describe('NPM v1 API Compatibility', () => {
|
|
238
|
-
it('should redirect /-/v1/search to /-/search', async () => {
|
|
239
|
-
const res = await app.request(
|
|
240
|
-
'/-/v1/search?text=lodash',
|
|
241
|
-
{},
|
|
242
|
-
env,
|
|
243
|
-
)
|
|
244
|
-
expect(res.status).toBe(308)
|
|
245
|
-
expect(res.headers.get('location')).toBe('/-/search')
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('should preserve query parameters in redirects', async () => {
|
|
249
|
-
const res = await app.request(
|
|
250
|
-
'/-/v1/search?text=lodash&size=20',
|
|
251
|
-
{},
|
|
252
|
-
env,
|
|
253
|
-
)
|
|
254
|
-
expect(res.status).toBe(308)
|
|
255
|
-
expect(res.headers.get('location')).toBe('/-/search')
|
|
256
|
-
})
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
describe('Search Performance and Limits', () => {
|
|
261
|
-
describe('Response Time', () => {
|
|
262
|
-
it('should respond within reasonable time limits', async () => {
|
|
263
|
-
const startTime = Date.now()
|
|
264
|
-
const res = await app.request(
|
|
265
|
-
'/-/search?text=lodash',
|
|
266
|
-
{},
|
|
267
|
-
env,
|
|
268
|
-
)
|
|
269
|
-
const endTime = Date.now()
|
|
270
|
-
|
|
271
|
-
expect(res.status).toBe(200)
|
|
272
|
-
expect(endTime - startTime).toBeLessThan(5000) // 5 second timeout
|
|
273
|
-
})
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
describe('Large Result Sets', () => {
|
|
277
|
-
it('should handle searches with many results', async () => {
|
|
278
|
-
const res = await app.request('/-/search?text=test', {}, env)
|
|
279
|
-
expect(res.status).toBe(200)
|
|
280
|
-
const data = (await res.json()) as any
|
|
281
|
-
expect(data).toBeDefined()
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
it('should handle pagination for large result sets', async () => {
|
|
285
|
-
const res = await app.request(
|
|
286
|
-
'/-/search?text=test&size=50&from=100',
|
|
287
|
-
{},
|
|
288
|
-
env,
|
|
289
|
-
)
|
|
290
|
-
expect(res.status).toBe(200)
|
|
291
|
-
})
|
|
292
|
-
})
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
describe('Error Handling', () => {
|
|
296
|
-
describe('Invalid Parameters', () => {
|
|
297
|
-
it('should handle invalid quality parameter', async () => {
|
|
298
|
-
const res = await app.request(
|
|
299
|
-
'/-/search?text=lodash&quality=invalid',
|
|
300
|
-
{},
|
|
301
|
-
env,
|
|
302
|
-
)
|
|
303
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
it('should handle invalid popularity parameter', async () => {
|
|
307
|
-
const res = await app.request(
|
|
308
|
-
'/-/search?text=lodash&popularity=2.0',
|
|
309
|
-
{},
|
|
310
|
-
env,
|
|
311
|
-
)
|
|
312
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
it('should handle invalid maintenance parameter', async () => {
|
|
316
|
-
const res = await app.request(
|
|
317
|
-
'/-/search?text=lodash&maintenance=-0.5',
|
|
318
|
-
{},
|
|
319
|
-
env,
|
|
320
|
-
)
|
|
321
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
it('should handle very long search terms', async () => {
|
|
325
|
-
const longTerm = 'a'.repeat(1000)
|
|
326
|
-
const res = await app.request(
|
|
327
|
-
`/-/search?text=${longTerm}`,
|
|
328
|
-
{},
|
|
329
|
-
env,
|
|
330
|
-
)
|
|
331
|
-
expect([200, 400, 414].includes(res.status)).toBe(true)
|
|
332
|
-
})
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
describe('Malformed Requests', () => {
|
|
336
|
-
it('should handle malformed query parameters', async () => {
|
|
337
|
-
const res = await app.request('/-/search?text=', {}, env)
|
|
338
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
it('should handle missing required parameters gracefully', async () => {
|
|
342
|
-
const res = await app.request('/-/search', {}, env)
|
|
343
|
-
expect([200, 400].includes(res.status)).toBe(true)
|
|
344
|
-
})
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
describe('Upstream Errors', () => {
|
|
348
|
-
it('should handle upstream registry connection errors', async () => {
|
|
349
|
-
const res = await app.request(
|
|
350
|
-
'/nonexistent/-/search?text=lodash',
|
|
351
|
-
{},
|
|
352
|
-
env,
|
|
353
|
-
)
|
|
354
|
-
expect([200, 404, 502].includes(res.status)).toBe(true)
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
it('should handle upstream registry timeout errors', async () => {
|
|
358
|
-
const res = await app.request(
|
|
359
|
-
'/npm/-/search?text=lodash',
|
|
360
|
-
{},
|
|
361
|
-
env,
|
|
362
|
-
)
|
|
363
|
-
// May return 502 due to upstream connection issues in test environment
|
|
364
|
-
expect([200, 502].includes(res.status)).toBe(true)
|
|
365
|
-
})
|
|
366
|
-
})
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
describe('Response Headers and Caching', () => {
|
|
370
|
-
describe('Content-Type Headers', () => {
|
|
371
|
-
it('should set appropriate content-type headers', async () => {
|
|
372
|
-
const res = await app.request(
|
|
373
|
-
'/-/search?text=lodash',
|
|
374
|
-
{},
|
|
375
|
-
env,
|
|
376
|
-
)
|
|
377
|
-
expect(res.headers.get('content-type')).toContain(
|
|
378
|
-
'application/json',
|
|
379
|
-
)
|
|
380
|
-
})
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
describe('Cache Control', () => {
|
|
384
|
-
it('should set appropriate cache-control headers', async () => {
|
|
385
|
-
const res = await app.request(
|
|
386
|
-
'/-/search?text=lodash',
|
|
387
|
-
{},
|
|
388
|
-
env,
|
|
389
|
-
)
|
|
390
|
-
// Cache headers would be validated based on implementation
|
|
391
|
-
expect(res.status).toBe(200)
|
|
392
|
-
})
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
describe('CORS Headers', () => {
|
|
396
|
-
it('should handle CORS headers for search requests', async () => {
|
|
397
|
-
const res = await app.request(
|
|
398
|
-
'/-/search?text=lodash',
|
|
399
|
-
{
|
|
400
|
-
headers: {
|
|
401
|
-
Origin: 'https://example.com',
|
|
402
|
-
},
|
|
403
|
-
},
|
|
404
|
-
env,
|
|
405
|
-
)
|
|
406
|
-
expect(res.status).toBe(200)
|
|
407
|
-
// CORS headers would be validated based on implementation
|
|
408
|
-
})
|
|
409
|
-
})
|
|
410
|
-
})
|
|
411
|
-
|
|
412
|
-
describe('Special Search Cases', () => {
|
|
413
|
-
describe('Package Name Patterns', () => {
|
|
414
|
-
it('should handle exact package name matches', async () => {
|
|
415
|
-
const res = await app.request(
|
|
416
|
-
'/-/search?text=lodash',
|
|
417
|
-
{},
|
|
418
|
-
env,
|
|
419
|
-
)
|
|
420
|
-
expect(res.status).toBe(200)
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
it('should handle partial package name matches', async () => {
|
|
424
|
-
const res = await app.request('/-/search?text=lod', {}, env)
|
|
425
|
-
expect(res.status).toBe(200)
|
|
426
|
-
})
|
|
427
|
-
|
|
428
|
-
it('should handle keyword searches', async () => {
|
|
429
|
-
const res = await app.request(
|
|
430
|
-
'/-/search?text=utility',
|
|
431
|
-
{},
|
|
432
|
-
env,
|
|
433
|
-
)
|
|
434
|
-
expect(res.status).toBe(200)
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
it('should handle author searches', async () => {
|
|
438
|
-
const res = await app.request(
|
|
439
|
-
'/-/search?text=author:john',
|
|
440
|
-
{},
|
|
441
|
-
env,
|
|
442
|
-
)
|
|
443
|
-
expect(res.status).toBe(200)
|
|
444
|
-
})
|
|
445
|
-
})
|
|
446
|
-
|
|
447
|
-
describe('Advanced Search Features', () => {
|
|
448
|
-
it('should handle boolean search operators', async () => {
|
|
449
|
-
const res = await app.request(
|
|
450
|
-
'/-/search?text=lodash+utility',
|
|
451
|
-
{},
|
|
452
|
-
env,
|
|
453
|
-
)
|
|
454
|
-
expect(res.status).toBe(200)
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
it('should handle quoted search terms', async () => {
|
|
458
|
-
const res = await app.request(
|
|
459
|
-
'/-/search?text="utility library"',
|
|
460
|
-
{},
|
|
461
|
-
env,
|
|
462
|
-
)
|
|
463
|
-
expect(res.status).toBe(200)
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
it('should handle wildcard searches', async () => {
|
|
467
|
-
const res = await app.request('/-/search?text=lod*', {}, env)
|
|
468
|
-
expect(res.status).toBe(200)
|
|
469
|
-
})
|
|
470
|
-
})
|
|
471
|
-
})
|
|
472
|
-
})
|
package/test/setup.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
// Cloudflare Workers test setup using @cloudflare/vitest-pool-workers
|
|
2
|
-
import { beforeEach, afterEach, afterAll } from 'vitest'
|
|
3
|
-
import { env } from 'cloudflare:test'
|
|
4
|
-
|
|
5
|
-
beforeEach(async () => {
|
|
6
|
-
// Set environment variables that the app expects
|
|
7
|
-
process.env.ARG_DEBUG = 'false'
|
|
8
|
-
process.env.ARG_TELEMETRY = 'false'
|
|
9
|
-
process.env.ARG_DAEMON = 'false'
|
|
10
|
-
|
|
11
|
-
// With @cloudflare/vitest-pool-workers, real bindings are automatically provided
|
|
12
|
-
// and isolated per test. We can set up test data here if needed.
|
|
13
|
-
|
|
14
|
-
// Set up test database with proper schema
|
|
15
|
-
try {
|
|
16
|
-
// Create tables with single-line SQL to avoid parsing issues
|
|
17
|
-
await env.DB.exec(
|
|
18
|
-
"CREATE TABLE IF NOT EXISTS packages (name TEXT PRIMARY KEY, tags TEXT, last_updated TEXT, origin TEXT NOT NULL DEFAULT 'local', upstream TEXT, cached_at TEXT)",
|
|
19
|
-
)
|
|
20
|
-
await env.DB.exec(
|
|
21
|
-
'CREATE TABLE IF NOT EXISTS tokens (token TEXT PRIMARY KEY, uuid TEXT NOT NULL, scope TEXT)',
|
|
22
|
-
)
|
|
23
|
-
await env.DB.exec(
|
|
24
|
-
"CREATE TABLE IF NOT EXISTS versions (spec TEXT PRIMARY KEY, manifest TEXT, published_at TEXT, origin TEXT NOT NULL DEFAULT 'local', upstream TEXT, cached_at TEXT)",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
// Insert a test admin token for authenticated tests
|
|
28
|
-
await env.DB.prepare(
|
|
29
|
-
'INSERT OR REPLACE INTO tokens (token, uuid, scope) VALUES (?, ?, ?)',
|
|
30
|
-
)
|
|
31
|
-
.bind('test-admin-token-12345', 'admin-uuid', 'read,write')
|
|
32
|
-
.run()
|
|
33
|
-
} catch (error) {
|
|
34
|
-
// Database might already be set up, that's okay
|
|
35
|
-
console.log('Database setup skipped:', error)
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
afterEach(async () => {
|
|
40
|
-
// Clean up test data after each test
|
|
41
|
-
// While Cloudflare Workers pool provides isolated storage per test,
|
|
42
|
-
// explicit cleanup ensures no test data leaks between tests
|
|
43
|
-
|
|
44
|
-
// Clean up database tables (ignore errors if tables don't exist)
|
|
45
|
-
await env.DB.exec(
|
|
46
|
-
'DELETE FROM packages WHERE name LIKE "test-%"',
|
|
47
|
-
).catch(() => {})
|
|
48
|
-
await env.DB.exec(
|
|
49
|
-
'DELETE FROM versions WHERE spec LIKE "test-%"',
|
|
50
|
-
).catch(() => {})
|
|
51
|
-
await env.DB.exec(
|
|
52
|
-
'DELETE FROM tokens WHERE token LIKE "test-%"',
|
|
53
|
-
).catch(() => {})
|
|
54
|
-
|
|
55
|
-
// Clean up any test objects from R2 bucket
|
|
56
|
-
const testObjects = await env.BUCKET.list({
|
|
57
|
-
prefix: 'test-',
|
|
58
|
-
}).catch(() => ({ objects: [] }))
|
|
59
|
-
for (const obj of testObjects.objects || []) {
|
|
60
|
-
await env.BUCKET.delete(obj.key).catch(() => {})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Clean up any test keys from KV store
|
|
64
|
-
if (env.KV) {
|
|
65
|
-
const testKvKeys = await env.KV.list({ prefix: 'test-' }).catch(
|
|
66
|
-
() => ({ keys: [] }),
|
|
67
|
-
)
|
|
68
|
-
for (const key of testKvKeys.keys || []) {
|
|
69
|
-
await env.KV.delete(key.name).catch(() => {})
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
console.log('โ Test cleanup completed')
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
afterAll(async () => {
|
|
77
|
-
// Global cleanup after all tests complete
|
|
78
|
-
console.log('๐งน Running global test cleanup...')
|
|
79
|
-
|
|
80
|
-
// Clean up all test data from database (ignore errors if tables don't exist)
|
|
81
|
-
await env.DB.exec(
|
|
82
|
-
'DELETE FROM packages WHERE name LIKE "test-%" OR name LIKE "%test%"',
|
|
83
|
-
).catch(() => {})
|
|
84
|
-
await env.DB.exec(
|
|
85
|
-
'DELETE FROM versions WHERE spec LIKE "test-%" OR spec LIKE "%test%"',
|
|
86
|
-
).catch(() => {})
|
|
87
|
-
await env.DB.exec(
|
|
88
|
-
'DELETE FROM tokens WHERE token LIKE "test-%" OR uuid LIKE "%test%"',
|
|
89
|
-
).catch(() => {})
|
|
90
|
-
|
|
91
|
-
// Clean up all test objects from R2 bucket
|
|
92
|
-
const allTestObjects = await env.BUCKET.list({
|
|
93
|
-
prefix: 'test-',
|
|
94
|
-
}).catch(() => ({ objects: [] }))
|
|
95
|
-
for (const obj of allTestObjects.objects || []) {
|
|
96
|
-
await env.BUCKET.delete(obj.key).catch(() => {})
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Also clean up any objects that might have test in the name
|
|
100
|
-
const moreTestObjects = await env.BUCKET.list().catch(() => ({
|
|
101
|
-
objects: [],
|
|
102
|
-
}))
|
|
103
|
-
for (const obj of moreTestObjects.objects || []) {
|
|
104
|
-
if (obj.key.includes('test')) {
|
|
105
|
-
await env.BUCKET.delete(obj.key).catch(() => {})
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Clean up all test keys from KV store
|
|
110
|
-
if (env.KV) {
|
|
111
|
-
const allTestKvKeys = await env.KV.list({
|
|
112
|
-
prefix: 'test-',
|
|
113
|
-
}).catch(() => ({ keys: [] }))
|
|
114
|
-
for (const key of allTestKvKeys.keys || []) {
|
|
115
|
-
await env.KV.delete(key.name).catch(() => {})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Clean up any KV keys that might have test in the name
|
|
119
|
-
const allKvKeys = await env.KV.list().catch(() => ({
|
|
120
|
-
keys: [],
|
|
121
|
-
}))
|
|
122
|
-
for (const key of allKvKeys.keys || []) {
|
|
123
|
-
if (key.name.includes('test')) {
|
|
124
|
-
await env.KV.delete(key.name).catch(() => {})
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
console.log('โ Global test cleanup completed successfully')
|
|
130
|
-
})
|