@@ -5,15 +5,16 @@ import type { Response, SuperAgent, SuperAgentRequest } from 'superagent';
55import type { SuperTest } from 'supertest' ;
66import { URL } from 'url' ;
77import { pipe } from 'fp-ts/function' ;
8+ import { Status } from '@api-ts/response' ;
89
910type SuccessfulResponses < Route extends h . HttpRoute > = {
10- [ Status in h . KnownHttpStatusCodes < Route [ 'response' ] > ] : {
11- status : Status ;
11+ [ R in h . KnownResponses < Route [ 'response' ] > ] : {
12+ status : h . HttpResponseCodes [ R ] ;
1213 error ?: undefined ;
13- body : t . TypeOf < Route [ 'response' ] [ Status ] > ;
14+ body : h . ResponseTypeForStatus < Route [ 'response' ] , R > ;
1415 original : Response ;
1516 } ;
16- } [ h . KnownHttpStatusCodes < Route [ 'response' ] > ] ;
17+ } [ h . KnownResponses < Route [ 'response' ] > ] ;
1718
1819type DecodedResponse < Route extends h . HttpRoute > =
1920 | SuccessfulResponses < Route >
@@ -28,17 +29,16 @@ const decodedResponse = <Route extends h.HttpRoute>(res: DecodedResponse<Route>)
2829
2930type ExpectedDecodedResponse <
3031 Route extends h . HttpRoute ,
31- Status extends h . KnownHttpStatusCodes < Route [ 'response' ] > ,
32- > = {
33- body : t . TypeOf < Route [ 'response' ] [ Status ] > ;
34- original : Response ;
35- } ;
32+ StatusCode extends h . HttpResponseCodes [ h . KnownResponses < Route [ 'response' ] > ] ,
33+ > = DecodedResponse < Route > & { status : StatusCode } ;
3634
3735type PatchedRequest < Req extends SuperAgentRequest , Route extends h . HttpRoute > = Req & {
3836 decode : ( ) => Promise < DecodedResponse < Route > > ;
39- decodeExpecting : < Status extends h . KnownHttpStatusCodes < Route [ 'response' ] > > (
40- status : Status ,
41- ) => Promise < ExpectedDecodedResponse < Route , Status > > ;
37+ decodeExpecting : <
38+ StatusCode extends h . HttpResponseCodes [ h . KnownResponses < Route [ 'response' ] > ] ,
39+ > (
40+ status : StatusCode ,
41+ ) => Promise < ExpectedDecodedResponse < Route , StatusCode > > ;
4242} ;
4343
4444type SuperagentMethod = 'get' | 'post' | 'put' | 'delete' ;
@@ -84,6 +84,13 @@ export const supertestRequestFactory =
8484 return supertest [ method ] ( path ) ;
8585 } ;
8686
87+ const hasCodecForStatus = < S extends Status > (
88+ responses : h . HttpResponse ,
89+ status : S ,
90+ ) : responses is { [ K in S ] : t . Mixed } => {
91+ return status in responses && responses [ status ] !== undefined ;
92+ } ;
93+
8794const patchRequest = < Req extends SuperAgentRequest , Route extends h . HttpRoute > (
8895 route : Route ,
8996 req : Req ,
@@ -94,11 +101,11 @@ const patchRequest = <Req extends SuperAgentRequest, Route extends h.HttpRoute>(
94101 req . then ( ( res ) => {
95102 const { body, status : statusCode } = res ;
96103
97- let status : string | undefined ;
104+ let status : Status | undefined ;
98105 // DISCUSS: Should we have this as a preprocessed const in io-ts-http?
99106 for ( const [ name , code ] of Object . entries ( h . HttpResponseCodes ) ) {
100107 if ( statusCode === code ) {
101- status = name ;
108+ status = name as Status ;
102109 break ;
103110 }
104111 }
@@ -111,7 +118,7 @@ const patchRequest = <Req extends SuperAgentRequest, Route extends h.HttpRoute>(
111118 } ) ;
112119 }
113120
114- if ( route . response [ status ] === undefined ) {
121+ if ( ! hasCodecForStatus ( route . response , status ) ) {
115122 return decodedResponse ( {
116123 // DISCUSS: what's this non-standard HTTP status code?
117124 status : 'decodeError' ,
@@ -124,10 +131,12 @@ const patchRequest = <Req extends SuperAgentRequest, Route extends h.HttpRoute>(
124131 route . response [ status ] . decode ( res . body ) ,
125132 E . map ( ( body ) =>
126133 decodedResponse < Route > ( {
127- status : statusCode ,
134+ status : statusCode as h . HttpResponseCodes [ h . KnownResponses <
135+ Route [ 'response' ]
136+ > ] ,
128137 body,
129138 original : res ,
130- } ) ,
139+ } as SuccessfulResponses < Route > ) ,
131140 ) ,
132141 E . getOrElse ( ( error ) =>
133142 // DISCUSS: what's this non-standard HTTP status code?
@@ -142,19 +151,16 @@ const patchRequest = <Req extends SuperAgentRequest, Route extends h.HttpRoute>(
142151 } ) ;
143152
144153 patchedReq . decodeExpecting = <
145- Status extends h . KnownHttpStatusCodes < Route [ 'response' ] > ,
154+ StatusCode extends h . HttpResponseCodes [ h . KnownResponses < Route [ 'response' ] > ] ,
146155 > (
147- status : Status ,
156+ status : StatusCode ,
148157 ) =>
149158 patchedReq . decode ( ) . then ( ( res ) => {
150159 if ( res . status !== status ) {
151160 const error = res . error ?? `Unexpected status code ${ res . status } ` ;
152161 throw new Error ( JSON . stringify ( error ) ) ;
153162 } else {
154- return {
155- body : res . body ,
156- original : res . original ,
157- } ;
163+ return res as ExpectedDecodedResponse < Route , StatusCode > ;
158164 }
159165 } ) ;
160166 return patchedReq ;
0 commit comments