fetch's redirect modes lost their only end-to-end test when #11101 deleted the reqwest fallback, and the replacement only pins the enum translation. The behaviour is correct today — verified by hand against the oracle — but nothing in CI would catch it regressing.
What was lost and why
#11066 (redirect modes + response metadata) originally shipped redirect_clients_expose_follow_and_manual_responses: it stood up a TcpListener and drove two reqwest::Clients against a real 302. #11101 deleted perry-stdlib's reqwest fallback, so that test's subject no longer exists and it was dropped during the re-port.
What remains is fetch_redirect_mode_maps_onto_the_engines_redirect_mode, which asserts that FetchRedirectMode translates to turnloop_http::client::RedirectMode. That is worth having, but it only pins the enum mapping — the engine's own follow / manual / error behaviour, and the redirected and final-url metadata that go with it, are now untested in this repo.
The behaviour is right today
Built perry plus the static wrappers, compiled a four-mode probe against a local 302 server, and ran the same .ts under the pinned oracle:
=== PERRY ===
follow status=200 redirected=true url=http://127.0.0.1:53385/final loc=null
manual status=302 redirected=false url=http://127.0.0.1:53385/start loc=/final
error threw TypeError: fetch failed
bogus threw TypeError: Request redirect mode must be follow, error, or manual
=== NODE v26.5.1 ===
follow status=200 redirected=true url=http://127.0.0.1:53385/final loc=null
manual status=302 redirected=false url=http://127.0.0.1:53385/start loc=/final
error threw TypeError: fetch failed
bogus threw TypeError: undefined: bogus is not an accepted type. Expected one of follow, manual, error.
The three real modes match byte-for-byte, including redirected and url. That probe is not a committed test.
Two things to decide
-
Add an engine round-trip test. There is no existing idiom in perry-stdlib's tests for driving the turnloop engine against a local server, which is why the re-port did not invent one rather than guess at a shape the codebase would want. A gap fixture may be the better home, since those are diffed byte-for-byte against Node and would cover redirected / url for free.
-
The invalid-mode message diverges from Node, as the last line above shows. Both throw TypeError and both reject, so nothing is broken — but a gap test covering an invalid redirect value would fail on the text. That wording predates the re-port; changing it is a behaviour call nobody has made.
Found while re-porting #11066 onto a main where the reqwest path no longer exists.
fetch's redirect modes lost their only end-to-end test when #11101 deleted the reqwest fallback, and the replacement only pins the enum translation. The behaviour is correct today — verified by hand against the oracle — but nothing in CI would catch it regressing.What was lost and why
#11066 (redirect modes + response metadata) originally shipped
redirect_clients_expose_follow_and_manual_responses: it stood up aTcpListenerand drove tworeqwest::Clients against a real 302. #11101 deleted perry-stdlib's reqwest fallback, so that test's subject no longer exists and it was dropped during the re-port.What remains is
fetch_redirect_mode_maps_onto_the_engines_redirect_mode, which asserts thatFetchRedirectModetranslates toturnloop_http::client::RedirectMode. That is worth having, but it only pins the enum mapping — the engine's own follow / manual / error behaviour, and theredirectedand final-urlmetadata that go with it, are now untested in this repo.The behaviour is right today
Built
perryplus the static wrappers, compiled a four-mode probe against a local 302 server, and ran the same.tsunder the pinned oracle:The three real modes match byte-for-byte, including
redirectedandurl. That probe is not a committed test.Two things to decide
Add an engine round-trip test. There is no existing idiom in
perry-stdlib's tests for driving the turnloop engine against a local server, which is why the re-port did not invent one rather than guess at a shape the codebase would want. A gap fixture may be the better home, since those are diffed byte-for-byte against Node and would coverredirected/urlfor free.The invalid-mode message diverges from Node, as the last line above shows. Both throw
TypeErrorand both reject, so nothing is broken — but a gap test covering an invalidredirectvalue would fail on the text. That wording predates the re-port; changing it is a behaviour call nobody has made.Found while re-porting #11066 onto a main where the reqwest path no longer exists.