1- import type { Response } from "@cloudflare/workers-types" ;
21import ezSpawn from "@jsdevtools/ez-spawn" ;
32import { simulation } from "@simulacrum/github-api-simulator" ;
43import fs from "node:fs/promises" ;
@@ -14,11 +13,20 @@ const E2E_TEMP_DIR_PREFIX = "pkg-pr-new-e2e-";
1413
1514let server : Awaited < ReturnType < ReturnType < typeof simulation > [ "listen" ] > > ;
1615let workerUrl : string ;
17- let githubOutputDir : string ;
16+ let tempDir : string ;
1817let githubOutputPath : string ;
1918
2019let worker : UnstableDevWorker ;
20+
21+ const { stdout : gitHeadSha } = await ezSpawn . async ( "git rev-parse HEAD" , {
22+ stdio : "overlapped" ,
23+ } ) ;
24+ const fullSha = gitHeadSha . trim ( ) ;
25+ const sha = fullSha . substring ( 0 , 7 ) ;
26+
2127beforeAll ( async ( ) => {
28+ tempDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , E2E_TEMP_DIR_PREFIX ) ) ;
29+
2230 const app = simulation ( {
2331 initialState : {
2432 users : [ ] ,
@@ -51,15 +59,12 @@ beforeAll(async () => {
5159 `${ import . meta. dirname } /dist/_worker.js/index.js` ,
5260 {
5361 config : `${ import . meta. dirname } /wrangler.toml` ,
62+ persistTo : path . join ( tempDir , "worker" ) ,
5463 } ,
5564 ) ;
5665 const url = `${ worker . proxyData . userWorkerUrl . protocol } //${ worker . proxyData . userWorkerUrl . hostname } :${ worker . proxyData . userWorkerUrl . port } ` ;
5766 workerUrl = url ;
58-
59- githubOutputDir = await fs . mkdtemp (
60- path . join ( os . tmpdir ( ) , E2E_TEMP_DIR_PREFIX ) ,
61- ) ;
62- githubOutputPath = path . join ( githubOutputDir , "output" ) ;
67+ githubOutputPath = path . join ( tempDir , "output" ) ;
6368 await fs . writeFile ( githubOutputPath , "" ) ;
6469
6570 await ezSpawn . async (
@@ -74,8 +79,8 @@ beforeAll(async () => {
7479
7580afterAll ( async ( ) => {
7681 await server . ensureClose ( ) ;
77- if ( githubOutputDir ?. includes ( E2E_TEMP_DIR_PREFIX ) ) {
78- await fs . rm ( githubOutputDir , { recursive : true , force : true } ) ;
82+ if ( tempDir ?. includes ( E2E_TEMP_DIR_PREFIX ) ) {
83+ await fs . rm ( tempDir , { recursive : true , force : true } ) ;
7984 }
8085} ) ;
8186
@@ -147,14 +152,10 @@ describe.sequential.each([
147152 expect ( process . stderr ) . toContain ( "pkg-pr-new:" ) ;
148153 expect ( process . stderr ) . toContain ( "playground-a:" ) ;
149154 expect ( process . stderr ) . toContain ( "playground-b:" ) ;
150- } , 10_000 ) ;
155+ } , 20_000 ) ;
151156
152157 it ( `serves and installs playground-a for ${ mode } ` , async ( ) => {
153158 const [ owner , repo ] = payload . repository . full_name . split ( "/" ) ;
154- const { stdout : gitHeadSha } = await ezSpawn . async ( "git rev-parse HEAD" , {
155- stdio : "overlapped" ,
156- } ) ;
157- const sha = gitHeadSha . trim ( ) . substring ( 0 , 7 ) ;
158159 const ref = pr ?. payload . number ?? payload . workflow_run . head_branch ;
159160
160161 // Test download with SHA
@@ -166,9 +167,15 @@ describe.sequential.each([
166167 expect ( shaBlob . size ) . toBeGreaterThan ( 0 ) ;
167168
168169 // Test download with ref matches SHA content
169- const refResponse = await fetchWithRedirect (
170+ const refResponse = await worker . fetch (
170171 `/${ owner } /${ repo } /playground-a@${ ref } ` ,
171172 ) ;
173+ expect ( refResponse . status ) . toBe ( 200 ) ;
174+ expect ( refResponse . headers . get ( "x-pkg-name-key" ) ) . toBe ( "playground-a" ) ;
175+ expect ( refResponse . headers . get ( "x-commit-key" ) ) . toBe (
176+ `${ owner } :${ repo } :${ fullSha } ` ,
177+ ) ;
178+
172179 const refBlob = await refResponse . blob ( ) ;
173180 const shaBlobSize = await shaBlob . arrayBuffer ( ) ;
174181 const refBlobSize = await refBlob . arrayBuffer ( ) ;
@@ -190,14 +197,31 @@ describe.sequential.each([
190197 expect ( installProcess . stdout ) . toContain (
191198 "playground-a installed successfully!" ,
192199 ) ;
193- } , 10_000 ) ;
200+ } , 20_000 ) ;
201+
202+ it ( `returns metadata for HEAD requests (${ mode } )` , async ( ) => {
203+ const [ owner , repo ] = payload . repository . full_name . split ( "/" ) ;
204+
205+ const headResponse = await worker . fetch (
206+ `/${ owner } /${ repo } /playground-a@${ sha } ` ,
207+ { method : "HEAD" } ,
208+ ) ;
209+
210+ expect ( headResponse . status ) . toBe ( 200 ) ;
211+ expect ( headResponse . headers . get ( "x-pkg-name-key" ) ) . toBe ( "playground-a" ) ;
212+ expect ( headResponse . headers . get ( "x-commit-key" ) ) . toBe (
213+ `${ owner } :${ repo } :${ sha } ` ,
214+ ) ;
215+ expect ( headResponse . headers . get ( "content-type" ) ) . toBe (
216+ "application/tar+gzip" ,
217+ ) ;
218+ expect ( headResponse . headers . get ( "etag" ) ) . toBeDefined ( ) ;
219+ const lastModified = headResponse . headers . get ( "last-modified" ) ;
220+ expect ( new Date ( lastModified ! ) . toString ( ) ) . not . toBe ( "Invalid Date" ) ;
221+ } ) ;
194222
195223 it ( `serves and installs playground-b for ${ mode } ` , async ( ) => {
196224 const [ owner , repo ] = payload . repository . full_name . split ( "/" ) ;
197- const { stdout : gitHeadSha } = await ezSpawn . async ( "git rev-parse HEAD" , {
198- stdio : "overlapped" ,
199- } ) ;
200- const sha = gitHeadSha . trim ( ) . substring ( 0 , 7 ) ;
201225
202226 // Test download
203227 const response = await worker . fetch (
@@ -225,51 +249,60 @@ describe.sequential.each([
225249 expect ( installProcess . stdout ) . toContain (
226250 "playground-b installed successfully!" ,
227251 ) ;
228- } , 10_000 ) ;
252+ } , 20_000 ) ;
229253} ) ;
230254
231- describe ( "URL redirects " , ( ) => {
255+ describe ( "URL resolution " , ( ) => {
232256 describe ( "standard packages" , ( ) => {
233- it ( "redirects full URLs correctly" , async ( ) => {
234- const response = await fetchWithRedirect ( "/tinylibs/tinybench@a832a55" ) ;
235- expect ( response . url ) . toContain ( "/tinylibs/tinybench/tinybench@a832a55" ) ;
257+ it . each ( [
258+ [ "full" , "/tinylibs/tinybench/tinybench@a832a55" ] ,
259+ [ "compact" , "/tinybench@a832a55" ] ,
260+ [ "with .tgz extension" , "/tinybench@a832a55.tgz" ] ,
261+ ] ) ( "resolves %s URLs" , async ( _ , url ) => {
262+ const response = await worker . fetch ( url ) ;
263+
264+ expect ( response . headers . get ( "x-commit-key" ) ) . toBe (
265+ "tinylibs:tinybench:a832a55" ,
266+ ) ;
267+ expect ( response . headers . get ( "x-pkg-name-key" ) ) . toBe ( "tinybench" ) ;
236268 } ) ;
237269
238- it ( "redirects compact URLs correctly" , async ( ) => {
239- const response = await fetchWithRedirect ( "/tinybench@a832a55" ) ;
240- expect ( response . url ) . toContain ( "/tinylibs/tinybench/tinybench@a832a55" ) ;
270+ it ( "resolves URL with full Git SHA" , async ( ) => {
271+ const response = await worker . fetch (
272+ "/tinylibs/tinybench/tinybench@a832a55e8f50c419ed8414024899e37e69b1f999" ,
273+ ) ;
274+
275+ expect ( response . headers . get ( "x-pkg-name-key" ) ) . toBe ( "tinybench" ) ;
276+ expect ( response . headers . get ( "x-commit-key" ) ) . toBe (
277+ "tinylibs:tinybench:a832a55e8f50c419ed8414024899e37e69b1f999" ,
278+ ) ;
241279 } ) ;
242280 } ) ;
243281
244282 describe ( "scoped packages" , ( ) => {
245- const expectedPath = `/stackblitz/sdk/${ encodeURIComponent ( "@stackblitz/sdk" ) } @a832a55` ;
283+ it . each ( [
284+ [ "full" , "/stackblitz/sdk/@stackblitz/sdk@a832a55" ] ,
285+ [ "encoded" , "/stackblitz/sdk/%40stackblitz%2Fsdk@a832a55" ] ,
286+ [ "compact" , "/@stackblitz/sdk@a832a55" ] ,
287+ [ "compact encoded" , "/%40stackblitz%2Fsdk@a832a55" ] ,
288+ ] ) ( "resolves %s URLs" , async ( _ , url ) => {
289+ const response = await worker . fetch ( url ) ;
246290
247- it ( "redirects full scoped package URLs correctly" , async ( ) => {
248- const response = await fetchWithRedirect (
249- "/ stackblitz/ sdk/@stackblitz/sdk@ a832a55" ,
291+ expect ( response . headers . get ( "x-pkg-name-key" ) ) . toBe ( "@stackblitz:sdk" ) ;
292+ expect ( response . headers . get ( "x-commit-key" ) ) . toBe (
293+ "stackblitz: sdk: a832a55" ,
250294 ) ;
251- expect ( response . url ) . toContain ( expectedPath ) ;
252295 } ) ;
253296
254- it ( "redirects compact scoped package URLs correctly" , async ( ) => {
255- const response = await fetchWithRedirect ( "/@stackblitz/sdk@a832a55" ) ;
256- expect ( response . url ) . toContain ( expectedPath ) ;
297+ it ( "resolves URL with full Git SHA" , async ( ) => {
298+ const response = await worker . fetch (
299+ "/stackblitz/sdk/@stackblitz/sdk@a832a55e8f50c419ed8414024899e37e69b1f999" ,
300+ ) ;
301+
302+ expect ( response . headers . get ( "x-pkg-name-key" ) ) . toBe ( "@stackblitz:sdk" ) ;
303+ expect ( response . headers . get ( "x-commit-key" ) ) . toBe (
304+ "stackblitz:sdk:a832a55e8f50c419ed8414024899e37e69b1f999" ,
305+ ) ;
257306 } ) ;
258307 } ) ;
259308} ) ;
260-
261- async function fetchWithRedirect (
262- url : string ,
263- maxRedirects = 999 ,
264- ) : Promise < Response > {
265- const response = await worker . fetch ( url , { redirect : "manual" } ) ;
266-
267- if ( response . status >= 300 && response . status < 400 && maxRedirects > 0 ) {
268- const location = response . headers . get ( "location" ) ;
269- if ( location ) {
270- return fetchWithRedirect ( location , maxRedirects - 1 ) ;
271- }
272- }
273-
274- return response as unknown as Response ;
275- }
0 commit comments