@@ -4,14 +4,16 @@ import createClient, {
4
4
type BodySerializer ,
5
5
type FetchOptions ,
6
6
type MethodResponse ,
7
+ type FetchOptions ,
8
+ type HeadersOptions ,
7
9
type Middleware ,
8
10
type MiddlewareCallbackParams ,
9
11
type QuerySerializerOptions ,
10
12
type Client ,
11
13
type PathBasedClient ,
12
14
createPathBasedClient ,
13
15
} from "../src/index.js" ;
14
- import { server , baseUrl , useMockRequestHandler , toAbsoluteURL } from "./fixtures/mock-server.js" ;
16
+ import { baseUrl , server , toAbsoluteURL , useMockRequestHandler } from "./fixtures/mock-server.js" ;
15
17
import type { paths } from "./fixtures/api.js" ;
16
18
17
19
beforeAll ( ( ) => {
@@ -819,12 +821,7 @@ describe("client", () => {
819
821
await client . GET ( "/self" ) ;
820
822
821
823
// assert default headers were passed
822
- expect ( getRequest ( ) . headers ) . toEqual (
823
- new Headers ( {
824
- ...headers , // assert new header got passed
825
- "Content-Type" : "application/json" , // probably doesn’t need to get tested, but this was simpler than writing lots of code to ignore these
826
- } ) ,
827
- ) ;
824
+ expect ( getRequest ( ) . headers ) . toEqual ( new Headers ( headers ) ) ;
828
825
} ) ;
829
826
830
827
it ( "can be overridden" , async ( ) => {
@@ -850,7 +847,6 @@ describe("client", () => {
850
847
expect ( getRequest ( ) . headers ) . toEqual (
851
848
new Headers ( {
852
849
"Cache-Control" : "no-cache" ,
853
- "Content-Type" : "application/json" ,
854
850
} ) ,
855
851
) ;
856
852
} ) ;
@@ -894,6 +890,139 @@ describe("client", () => {
894
890
} ) ;
895
891
} ) ;
896
892
893
+ describe ( "content-type" , ( ) => {
894
+ const BODY_ACCEPTING_METHODS = [ [ "PUT" ] , [ "POST" ] , [ "DELETE" ] , [ "OPTIONS" ] , [ "PATCH" ] ] as const ;
895
+ const ALL_METHODS = [ ...BODY_ACCEPTING_METHODS , [ "GET" ] , [ "HEAD" ] ] as const ;
896
+
897
+ const fireRequestAndGetContentType = async ( options : {
898
+ defaultHeaders ?: HeadersOptions ;
899
+ method : ( typeof ALL_METHODS ) [ number ] [ number ] ;
900
+ fetchOptions : FetchOptions < any > ;
901
+ } ) => {
902
+ const client = createClient < any > ( { baseUrl, headers : options . defaultHeaders } ) ;
903
+ const { getRequest } = useMockRequestHandler ( {
904
+ baseUrl,
905
+ method : "all" ,
906
+ path : "/blogposts-optional" ,
907
+ status : 200 ,
908
+ } ) ;
909
+ await client [ options . method ] ( "/blogposts-optional" , options . fetchOptions as any ) ;
910
+
911
+ const request = getRequest ( ) ;
912
+ return request . headers . get ( "content-type" ) ;
913
+ } ;
914
+
915
+ it . each ( ALL_METHODS ) ( "no content-type for body-less requests - %s" , async ( method ) => {
916
+ const contentType = await fireRequestAndGetContentType ( {
917
+ method,
918
+ fetchOptions : { } ,
919
+ } ) ;
920
+
921
+ expect ( contentType ) . toBe ( null ) ;
922
+ } ) ;
923
+
924
+ it . each ( ALL_METHODS ) ( "no content-type for `undefined` body requests - %s" , async ( method ) => {
925
+ const contentType = await fireRequestAndGetContentType ( {
926
+ method,
927
+ fetchOptions : {
928
+ body : undefined ,
929
+ } ,
930
+ } ) ;
931
+
932
+ expect ( contentType ) . toBe ( null ) ;
933
+ } ) ;
934
+
935
+ const BODIES = [ { prop : "a" } , { } , "" , "str" , null , false , 0 , 1 , new Date ( "2024-08-07T09:52:00.836Z" ) ] as const ;
936
+ // const BODIES = ["str"] as const;
937
+ const METHOD_BODY_COMBINATIONS = BODY_ACCEPTING_METHODS . flatMap ( ( [ method ] ) =>
938
+ BODIES . map ( ( body ) => [ method , body ] as const ) ,
939
+ ) ;
940
+
941
+ it . each ( METHOD_BODY_COMBINATIONS ) (
942
+ "implicit default content-type for body-full requests - %s, %j" ,
943
+ async ( method , body ) => {
944
+ const contentType = await fireRequestAndGetContentType ( {
945
+ method,
946
+ fetchOptions : {
947
+ body,
948
+ } ,
949
+ } ) ;
950
+
951
+ expect ( contentType ) . toBe ( "application/json" ) ;
952
+ } ,
953
+ ) ;
954
+
955
+ it . each ( METHOD_BODY_COMBINATIONS ) (
956
+ "provided default content-type for body-full requests - %s, %j" ,
957
+ async ( method , body ) => {
958
+ const contentType = await fireRequestAndGetContentType ( {
959
+ defaultHeaders : {
960
+ "content-type" : "application/my-json" ,
961
+ } ,
962
+ method,
963
+ fetchOptions : {
964
+ body,
965
+ } ,
966
+ } ) ;
967
+
968
+ expect ( contentType ) . toBe ( "application/my-json" ) ;
969
+ } ,
970
+ ) ;
971
+
972
+ it . each ( METHOD_BODY_COMBINATIONS ) (
973
+ "native-fetch default content-type for body-full requests, when default is suppressed - %s, %j" ,
974
+ async ( method , body ) => {
975
+ const contentType = await fireRequestAndGetContentType ( {
976
+ defaultHeaders : {
977
+ "content-type" : null ,
978
+ } ,
979
+ method,
980
+ fetchOptions : {
981
+ body,
982
+ } ,
983
+ } ) ;
984
+ // the fetch implementation won't allow sending a body without content-type,
985
+ // so it invents one up and sends it, hopefully this will be consistent across
986
+ // local environments and won't make the tests flaky
987
+ expect ( contentType ) . toBe ( "text/plain;charset=UTF-8" ) ;
988
+ } ,
989
+ ) ;
990
+
991
+ it . each ( METHOD_BODY_COMBINATIONS ) (
992
+ "specified content-type for body-full requests - %s, %j" ,
993
+ async ( method , body ) => {
994
+ const contentType = await fireRequestAndGetContentType ( {
995
+ method,
996
+ fetchOptions : {
997
+ body,
998
+ headers : {
999
+ "content-type" : "application/my-json" ,
1000
+ } ,
1001
+ } ,
1002
+ } ) ;
1003
+
1004
+ expect ( contentType ) . toBe ( "application/my-json" ) ;
1005
+ } ,
1006
+ ) ;
1007
+
1008
+ it . each ( METHOD_BODY_COMBINATIONS ) (
1009
+ "specified content-type for body-full requests, even when default is suppressed - %s, %j" ,
1010
+ async ( method , body ) => {
1011
+ const contentType = await fireRequestAndGetContentType ( {
1012
+ method,
1013
+ fetchOptions : {
1014
+ body,
1015
+ headers : {
1016
+ "content-type" : "application/my-json" ,
1017
+ } ,
1018
+ } ,
1019
+ } ) ;
1020
+
1021
+ expect ( contentType ) . toBe ( "application/my-json" ) ;
1022
+ } ,
1023
+ ) ;
1024
+ } ) ;
1025
+
897
1026
describe ( "fetch" , ( ) => {
898
1027
it ( "createClient" , async ( ) => {
899
1028
function createCustomFetch ( data : any ) {
0 commit comments