2020-03-13 08:06:25 -07:00
// Test tools
import zlib from 'zlib' ;
import crypto from 'crypto' ;
2020-05-20 23:50:31 -07:00
import http from 'http' ;
import fs from 'fs' ;
import stream from 'stream' ;
2020-06-10 13:31:35 -07:00
import path from 'path' ;
2020-03-13 08:06:25 -07:00
import { lookup } from 'dns' ;
import vm from 'vm' ;
2020-06-13 00:13:50 -07:00
import { TextEncoder } from 'util' ;
2016-10-10 11:50:04 -07:00
import chai from 'chai' ;
2016-10-10 12:05:02 -07:00
import chaiPromised from 'chai-as-promised' ;
import chaiIterator from 'chai-iterator' ;
2016-12-05 19:35:23 -08:00
import chaiString from 'chai-string' ;
2016-10-10 11:50:04 -07:00
import FormData from 'form-data' ;
2020-06-10 13:31:35 -07:00
import FormDataNode from 'formdata-node' ;
2020-05-23 22:36:22 -07:00
import delay from 'delay' ;
2021-03-04 07:01:38 -08:00
import AbortControllerMysticatea from 'abort-controller' ;
import abortControllerPolyfill from 'abortcontroller-polyfill/dist/abortcontroller.js' ;
const AbortControllerPolyfill = abortControllerPolyfill . AbortController ;
2020-05-20 23:50:31 -07:00
2020-03-13 08:06:25 -07:00
// Test subjects
import Blob from 'fetch-blob' ;
2020-05-20 23:50:31 -07:00
2020-03-13 08:06:25 -07:00
import fetch , {
FetchError ,
Headers ,
Request ,
Response
2020-05-20 23:50:31 -07:00
} from '../src/index.js' ;
2020-06-10 04:17:35 -07:00
import { FetchError as FetchErrorOrig } from '../src/errors/fetch-error.js' ;
2020-05-25 07:43:10 -07:00
import HeadersOrig , { fromRawHeaders } from '../src/headers.js' ;
2020-05-20 23:50:31 -07:00
import RequestOrig from '../src/request.js' ;
import ResponseOrig from '../src/response.js' ;
import Body , { getTotalBytes , extractContentType } from '../src/body.js' ;
import TestServer from './utils/server.js' ;
2018-07-21 22:13:01 -07:00
const {
Uint8Array : VMUint8Array
} = vm . runInNewContext ( 'this' ) ;
2016-10-10 11:50:04 -07:00
2020-05-20 23:50:31 -07:00
import chaiTimeout from './utils/chai-timeout.js' ;
2017-07-02 09:32:48 -07:00
2016-10-10 12:05:02 -07:00
chai . use ( chaiPromised ) ;
chai . use ( chaiIterator ) ;
2016-12-05 19:35:23 -08:00
chai . use ( chaiString ) ;
2020-03-13 08:06:25 -07:00
chai . use ( chaiTimeout ) ;
const { expect } = chai ;
2018-11-12 20:40:11 -08:00
2020-03-13 08:06:25 -07:00
function streamToPromise ( stream , dataHandler ) {
return new Promise ( ( resolve , reject ) => {
stream . on ( 'data' , ( ... args ) => {
Promise . resolve ( )
. then ( ( ) => dataHandler ( ... args ) )
. catch ( reject ) ;
} ) ;
stream . on ( 'end' , resolve ) ;
stream . on ( 'error' , reject ) ;
} ) ;
}
2017-01-23 07:54:28 -08:00
describe ( 'node-fetch' , ( ) => {
2020-06-13 02:34:59 -07:00
const local = new TestServer ( ) ;
let base ;
before ( async ( ) => {
await local . start ( ) ;
base = ` http:// ${ local . hostname } : ${ local . port } / ` ;
} ) ;
after ( async ( ) => {
return local . stop ( ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should return a promise' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2016-10-10 11:50:04 -07:00
const p = fetch ( url ) ;
2020-05-28 14:57:57 -07:00
expect ( p ) . to . be . an . instanceof ( Promise ) ;
2015-01-26 05:58:52 -08:00
expect ( p ) . to . have . property ( 'then' ) ;
2015-01-26 02:15:07 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should expose Headers, Response and Request constructors' , ( ) => {
2017-02-26 16:45:11 -08:00
expect ( FetchError ) . to . equal ( FetchErrorOrig ) ;
2017-01-14 20:50:10 -08:00
expect ( Headers ) . to . equal ( HeadersOrig ) ;
expect ( Response ) . to . equal ( ResponseOrig ) ;
expect ( Request ) . to . equal ( RequestOrig ) ;
2015-05-03 01:37:58 -07:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support proper toString output for Headers, Response and Request objects' , ( ) => {
2016-10-12 20:51:19 -07:00
expect ( new Headers ( ) . toString ( ) ) . to . equal ( '[object Headers]' ) ;
expect ( new Response ( ) . toString ( ) ) . to . equal ( '[object Response]' ) ;
expect ( new Request ( base ) . toString ( ) ) . to . equal ( '[object Request]' ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject with error if url is protocol relative' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = '//example.com/' ;
2020-05-31 08:15:27 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejectedWith ( TypeError , /Invalid URL/ ) ;
2015-01-26 05:58:52 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject with error if url is relative path' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = '/some/path' ;
2020-05-31 08:15:27 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejectedWith ( TypeError , /Invalid URL/ ) ;
2015-01-26 02:15:07 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject with error if protocol is unsupported' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = 'ftp://example.com/' ;
2020-05-31 08:15:27 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejectedWith ( TypeError , /URL scheme "ftp" is not supported/ ) ;
2015-01-26 02:15:07 -08:00
} ) ;
2020-06-10 13:31:35 -07:00
it ( 'should reject with error on network failure' , function ( ) {
this . timeout ( 5000 ) ;
2020-03-13 08:06:25 -07:00
const url = 'http://localhost:50000/' ;
return expect ( fetch ( url ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . include ( { type : 'system' , code : 'ECONNREFUSED' , errno : 'ECONNREFUSED' } ) ;
} ) ;
it ( 'error should contain system error if one occurred' , ( ) => {
const err = new FetchError ( 'a message' , 'system' , new Error ( 'an error' ) ) ;
return expect ( err ) . to . have . property ( 'erroredSysCall' ) ;
} ) ;
it ( 'error should not contain system error if none occurred' , ( ) => {
const err = new FetchError ( 'a message' , 'a type' ) ;
return expect ( err ) . to . not . have . property ( 'erroredSysCall' ) ;
} ) ;
2020-06-10 13:31:35 -07:00
it ( 'system error is extracted from failed requests' , function ( ) {
this . timeout ( 5000 ) ;
2018-03-04 20:29:12 -08:00
const url = 'http://localhost:50000/' ;
2016-04-05 06:20:42 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
2020-03-13 08:06:25 -07:00
. and . have . property ( 'erroredSysCall' ) ;
2015-01-26 09:46:32 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should resolve into response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 05:11:26 -08:00
expect ( res ) . to . be . an . instanceof ( Response ) ;
expect ( res . headers ) . to . be . an . instanceof ( Headers ) ;
expect ( res . body ) . to . be . an . instanceof ( stream . Transform ) ;
expect ( res . bodyUsed ) . to . be . false ;
2015-01-27 07:33:06 -08:00
expect ( res . url ) . to . equal ( url ) ;
2015-01-27 20:17:12 -08:00
expect ( res . ok ) . to . be . true ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . statusText ) . to . equal ( 'OK' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'Response.redirect should resolve into response' , ( ) => {
const res = Response . redirect ( 'http://localhost' ) ;
expect ( res ) . to . be . an . instanceof ( Response ) ;
expect ( res . headers ) . to . be . an . instanceof ( Headers ) ;
expect ( res . headers . get ( 'location' ) ) . to . equal ( 'http://localhost/' ) ;
expect ( res . status ) . to . equal ( 302 ) ;
} ) ;
it ( 'Response.redirect /w invalid url should fail' , ( ) => {
expect ( ( ) => {
Response . redirect ( 'localhost' ) ;
} ) . to . throw ( ) ;
} ) ;
it ( 'Response.redirect /w invalid status should fail' , ( ) => {
expect ( ( ) => {
Response . redirect ( 'http://localhost' , 200 ) ;
} ) . to . throw ( ) ;
} ) ;
it ( 'should accept plain text response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } plain ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( res . bodyUsed ) . to . be . true ;
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'text' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should accept html response (like plain text)' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } html ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/html' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( res . bodyUsed ) . to . be . true ;
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( '<html></html>' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should accept json response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } json ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'application/json' ) ;
2016-10-10 11:50:04 -07:00
return res . json ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( res . bodyUsed ) . to . be . true ;
expect ( result ) . to . be . an ( 'object' ) ;
2020-03-13 08:06:25 -07:00
expect ( result ) . to . deep . equal ( { name : 'value' } ) ;
2015-01-27 07:33:06 -08:00
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should send request with custom headers' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
headers : { 'x-custom-header' : 'abc' }
2015-01-27 07:33:06 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 07:33:06 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers [ 'x-custom-header' ] ) . to . equal ( 'abc' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should accept headers instance' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
headers : new Headers ( { 'x-custom-header' : 'abc' } )
2015-04-22 08:36:11 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-04-22 08:36:11 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-04-22 08:36:11 -07:00
expect ( res . headers [ 'x-custom-header' ] ) . to . equal ( 'abc' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should accept custom host header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-07-11 04:38:26 -07:00
headers : {
host : 'example.com'
}
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-07-11 04:38:26 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2020-03-13 08:06:25 -07:00
expect ( res . headers . host ) . to . equal ( 'example.com' ) ;
2015-07-11 04:38:26 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should accept custom HoSt header' , ( ) => {
2018-03-22 22:01:45 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-22 22:01:45 -07:00
headers : {
HoSt : 'example.com'
}
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-03-22 22:01:45 -07:00
return res . json ( ) ;
} ) . then ( res => {
2020-03-13 08:06:25 -07:00
expect ( res . headers . host ) . to . equal ( 'example.com' ) ;
2018-03-22 22:01:45 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 301' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
2015-01-27 21:10:33 -08:00
expect ( res . ok ) . to . be . true ;
2015-01-27 07:33:06 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 302' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/302 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 303' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/303 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 307' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/307 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 308' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/308 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect chain' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/chain ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-01-27 07:33:06 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow POST request redirect code 301 with GET' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : 'a=1'
2015-09-28 07:30:41 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-09-28 07:30:41 -07:00
expect ( res . status ) . to . equal ( 200 ) ;
2016-10-10 11:50:04 -07:00
return res . json ( ) . then ( result => {
2015-09-28 07:30:41 -07:00
expect ( result . method ) . to . equal ( 'GET' ) ;
expect ( result . body ) . to . equal ( '' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow PATCH request redirect code 301 with PATCH' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PATCH' ,
body : 'a=1'
2018-03-04 19:29:59 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-03-04 19:29:59 -08:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
expect ( res . status ) . to . equal ( 200 ) ;
return res . json ( ) . then ( res => {
expect ( res . method ) . to . equal ( 'PATCH' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow POST request redirect code 302 with GET' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/302 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : 'a=1'
2015-09-28 07:30:41 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-09-28 07:30:41 -07:00
expect ( res . status ) . to . equal ( 200 ) ;
2016-10-10 11:50:04 -07:00
return res . json ( ) . then ( result => {
2015-09-28 07:30:41 -07:00
expect ( result . method ) . to . equal ( 'GET' ) ;
expect ( result . body ) . to . equal ( '' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow PATCH request redirect code 302 with PATCH' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/302 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PATCH' ,
body : 'a=1'
2018-03-04 19:29:59 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-03-04 19:29:59 -08:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
expect ( res . status ) . to . equal ( 200 ) ;
return res . json ( ) . then ( res => {
expect ( res . method ) . to . equal ( 'PATCH' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 303 with GET' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/303 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PUT' ,
body : 'a=1'
2015-09-28 07:30:41 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-09-28 07:30:41 -07:00
expect ( res . status ) . to . equal ( 200 ) ;
2016-10-10 11:50:04 -07:00
return res . json ( ) . then ( result => {
2015-09-28 07:30:41 -07:00
expect ( result . method ) . to . equal ( 'GET' ) ;
expect ( result . body ) . to . equal ( '' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow PATCH request redirect code 307 with PATCH' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/307 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PATCH' ,
body : 'a=1'
2018-03-04 19:29:59 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-03-04 19:29:59 -08:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
expect ( res . status ) . to . equal ( 200 ) ;
return res . json ( ) . then ( result => {
expect ( result . method ) . to . equal ( 'PATCH' ) ;
expect ( result . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should not follow non-GET redirect if body is a readable stream' , ( ) => {
2018-03-25 11:51:37 -07:00
const url = ` ${ base } redirect/307 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-25 11:51:37 -07:00
method : 'PATCH' ,
2020-06-10 04:16:51 -07:00
body : stream . Readable . from ( 'tada' )
2018-03-25 11:51:37 -07:00
} ;
2020-03-13 08:06:25 -07:00
return expect ( fetch ( url , options ) ) . to . eventually . be . rejected
2018-03-25 11:51:37 -07:00
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'unsupported-redirect' ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should obey maximum redirect, reject case' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/chain ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-27 07:33:06 -08:00
follow : 1
2020-03-13 08:06:25 -07:00
} ;
return expect ( fetch ( url , options ) ) . to . eventually . be . rejected
2016-04-05 06:20:42 -07:00
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'max-redirect' ) ;
2015-01-27 07:33:06 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should obey redirect chain, resolve case' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/chain ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-09-11 07:02:39 -07:00
follow : 2
2020-03-13 08:06:25 -07:00
} ;
return fetch ( url , options ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2016-09-11 07:02:39 -07:00
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow not following redirect' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-03-19 09:22:23 -07:00
follow : 0
2020-03-13 08:06:25 -07:00
} ;
return expect ( fetch ( url , options ) ) . to . eventually . be . rejected
2016-04-05 06:20:42 -07:00
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'max-redirect' ) ;
2015-03-19 09:22:23 -07:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support redirect mode, manual flag' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-04-05 11:47:23 -07:00
redirect : 'manual'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-04-12 11:58:04 -07:00
expect ( res . url ) . to . equal ( url ) ;
2016-04-05 11:47:23 -07:00
expect ( res . status ) . to . equal ( 301 ) ;
2016-10-08 18:31:42 -07:00
expect ( res . headers . get ( 'location' ) ) . to . equal ( ` ${ base } inspect ` ) ;
2016-04-05 11:47:23 -07:00
} ) ;
} ) ;
2020-12-31 21:38:11 -08:00
it ( 'should support redirect mode, manual flag, broken Location header' , ( ) => {
const url = ` ${ base } redirect/bad-location ` ;
const options = {
redirect : 'manual'
} ;
return fetch ( url , options ) . then ( res => {
expect ( res . url ) . to . equal ( url ) ;
expect ( res . status ) . to . equal ( 301 ) ;
expect ( res . headers . get ( 'location' ) ) . to . equal ( ` ${ base } redirect/%C3%A2%C2%98%C2%83 ` ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support redirect mode, error flag' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-04-05 11:47:23 -07:00
redirect : 'error'
} ;
2020-03-13 08:06:25 -07:00
return expect ( fetch ( url , options ) ) . to . eventually . be . rejected
2016-04-05 11:47:23 -07:00
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'no-redirect' ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support redirect mode, manual flag when there is no redirect' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-04-12 11:58:04 -07:00
redirect : 'manual'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-04-12 11:58:04 -07:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . headers . get ( 'location' ) ) . to . be . null ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should follow redirect code 301 and keep existing headers' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/301 ` ;
2020-03-13 08:06:25 -07:00
const options = {
headers : new Headers ( { 'x-custom-header' : 'abc' } )
2015-04-22 08:36:11 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-10-08 18:31:42 -07:00
expect ( res . url ) . to . equal ( ` ${ base } inspect ` ) ;
2015-04-22 08:36:11 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-04-22 08:36:11 -07:00
expect ( res . headers [ 'x-custom-header' ] ) . to . equal ( 'abc' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should treat broken redirect as ordinary response (follow)' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/no-location ` ;
return fetch ( url ) . then ( res => {
2018-03-04 19:29:59 -08:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . status ) . to . equal ( 301 ) ;
expect ( res . headers . get ( 'location' ) ) . to . be . null ;
} ) ;
2015-01-27 09:00:53 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should treat broken redirect as ordinary response (manual)' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } redirect/no-location ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-04-12 11:58:04 -07:00
redirect : 'manual'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-04-12 11:58:04 -07:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . status ) . to . equal ( 301 ) ;
expect ( res . headers . get ( 'location' ) ) . to . be . null ;
} ) ;
} ) ;
2020-12-31 21:38:44 -08:00
it ( 'should throw a TypeError on an invalid redirect option' , ( ) => {
const url = ` ${ base } redirect/301 ` ;
const options = {
redirect : 'foobar'
} ;
return fetch ( url , options ) . then ( ( ) => {
expect . fail ( ) ;
} , error => {
expect ( error ) . to . be . an . instanceOf ( TypeError ) ;
expect ( error . message ) . to . equal ( 'Redirect option \'foobar\' is not a valid value of RequestRedirect' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should set redirected property on response when redirect' , ( ) => {
2019-04-30 22:05:32 -07:00
const url = ` ${ base } redirect/301 ` ;
return fetch ( url ) . then ( res => {
expect ( res . redirected ) . to . be . true ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should not set redirected property on response without redirect' , ( ) => {
const url = ` ${ base } hello ` ;
2019-04-30 22:05:32 -07:00
return fetch ( url ) . then ( res => {
expect ( res . redirected ) . to . be . false ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should ignore invalid headers' , ( ) => {
2020-05-25 07:43:10 -07:00
const headers = fromRawHeaders ( [
'Invalid-Header ' ,
'abc\r\n' ,
'Invalid-Header-Value' ,
'\u0007k\r\n' ,
'Cookie' ,
'\u0007k\r\n' ,
'Cookie' ,
'\u0007kk\r\n'
] ) ;
expect ( headers ) . to . be . instanceOf ( Headers ) ;
expect ( headers . raw ( ) ) . to . deep . equal ( { } ) ;
2018-03-25 12:29:28 -07:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle client-error response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } error/400 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 09:00:53 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
expect ( res . status ) . to . equal ( 400 ) ;
expect ( res . statusText ) . to . equal ( 'Bad Request' ) ;
2015-01-27 20:17:12 -08:00
expect ( res . ok ) . to . be . false ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 09:00:53 -08:00
expect ( res . bodyUsed ) . to . be . true ;
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'client error' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle server-error response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } error/500 ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 09:00:53 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
expect ( res . status ) . to . equal ( 500 ) ;
expect ( res . statusText ) . to . equal ( 'Internal Server Error' ) ;
2015-01-27 20:17:12 -08:00
expect ( res . ok ) . to . be . false ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 09:00:53 -08:00
expect ( res . bodyUsed ) . to . be . true ;
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'server error' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle network-error response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } error/reset ` ;
2016-04-05 06:20:42 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'code' , 'ECONNRESET' ) ;
} ) ;
2020-05-23 05:28:38 -07:00
it ( 'should handle network-error partial response' , ( ) => {
const url = ` ${ base } error/premature ` ;
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . ok ) . to . be . true ;
return expect ( res . text ( ) ) . to . eventually . be . rejectedWith ( Error )
2020-06-09 17:26:24 -07:00
. and . have . property ( 'message' ) . matches ( /Premature close|The operation was aborted/ ) ;
2020-05-23 05:28:38 -07:00
} ) ;
} ) ;
2021-02-22 23:14:09 -08:00
it ( 'should handle network-error in chunked response' , ( ) => {
const url = ` ${ base } error/premature/chunked ` ;
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . ok ) . to . be . true ;
return expect ( new Promise ( ( resolve , reject ) => {
res . body . on ( 'error' , reject ) ;
res . body . on ( 'close' , resolve ) ;
} ) ) . to . eventually . be . rejectedWith ( Error , 'Premature close' )
. and . have . property ( 'code' , 'ERR_STREAM_PREMATURE_CLOSE' ) ;
} ) ;
} ) ;
it ( 'should handle network-error in chunked response async iterator' , ( ) => {
const url = ` ${ base } error/premature/chunked ` ;
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . ok ) . to . be . true ;
const read = async body => {
const chunks = [ ] ;
if ( process . version < 'v14' ) {
// In Node.js 12, some errors don't come out in the async iterator; we have to pick
// them up from the event-emitter and then throw them after the async iterator
let error ;
body . on ( 'error' , err => {
error = err ;
} ) ;
for await ( const chunk of body ) {
chunks . push ( chunk ) ;
}
if ( error ) {
throw error ;
}
return new Promise ( resolve => {
body . on ( 'close' , ( ) => resolve ( chunks ) ) ;
} ) ;
}
for await ( const chunk of body ) {
chunks . push ( chunk ) ;
}
return chunks ;
} ;
return expect ( read ( res . body ) )
. to . eventually . be . rejectedWith ( Error , 'Premature close' )
. and . have . property ( 'code' , 'ERR_STREAM_PREMATURE_CLOSE' ) ;
} ) ;
} ) ;
it ( 'should handle network-error in chunked response in consumeBody' , ( ) => {
const url = ` ${ base } error/premature/chunked ` ;
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . ok ) . to . be . true ;
return expect ( res . text ( ) )
. to . eventually . be . rejectedWith ( Error , 'Premature close' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle DNS-error response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = 'http://domain.invalid' ;
2016-04-05 06:20:42 -07:00
return expect ( fetch ( url ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
2020-06-09 17:26:24 -07:00
. and . have . property ( 'code' ) . that . matches ( /ENOTFOUND|EAI_AGAIN/ ) ;
2015-01-27 09:00:53 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject invalid json response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } error/json ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 21:01:10 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'application/json' ) ;
2020-03-13 08:06:25 -07:00
return expect ( res . json ( ) ) . to . eventually . be . rejectedWith ( Error ) ;
2015-01-27 21:01:10 -08:00
} ) ;
} ) ;
2021-02-28 12:05:23 -08:00
it ( 'should handle response with no status text' , ( ) => {
const url = ` ${ base } no-status-text ` ;
return fetch ( url ) . then ( res => {
expect ( res . statusText ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle no content response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } no-content ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 21:01:10 -08:00
expect ( res . status ) . to . equal ( 204 ) ;
expect ( res . statusText ) . to . equal ( 'No Content' ) ;
expect ( res . ok ) . to . be . true ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 21:01:10 -08:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . be . empty ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject when trying to parse no content response as json' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } no-content ` ;
2017-06-19 16:19:06 -07:00
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 204 ) ;
expect ( res . statusText ) . to . equal ( 'No Content' ) ;
expect ( res . ok ) . to . be . true ;
2020-03-13 08:06:25 -07:00
return expect ( res . json ( ) ) . to . eventually . be . rejectedWith ( Error ) ;
2017-06-19 16:19:06 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle no content response with gzip encoding' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } no-content/gzip ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-05-25 09:46:11 -07:00
expect ( res . status ) . to . equal ( 204 ) ;
expect ( res . statusText ) . to . equal ( 'No Content' ) ;
expect ( res . headers . get ( 'content-encoding' ) ) . to . equal ( 'gzip' ) ;
expect ( res . ok ) . to . be . true ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2016-05-25 09:46:11 -07:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . be . empty ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle not modified response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } not-modified ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-05-25 09:46:11 -07:00
expect ( res . status ) . to . equal ( 304 ) ;
expect ( res . statusText ) . to . equal ( 'Not Modified' ) ;
expect ( res . ok ) . to . be . false ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2016-05-25 09:46:11 -07:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . be . empty ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle not modified response with gzip encoding' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } not-modified/gzip ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-05-25 09:46:11 -07:00
expect ( res . status ) . to . equal ( 304 ) ;
expect ( res . statusText ) . to . equal ( 'Not Modified' ) ;
expect ( res . headers . get ( 'content-encoding' ) ) . to . equal ( 'gzip' ) ;
expect ( res . ok ) . to . be . false ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2016-05-25 09:46:11 -07:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . be . empty ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should decompress gzip response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } gzip ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should decompress slightly invalid gzip response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } gzip-truncated ` ;
2017-02-22 00:05:55 -08:00
return fetch ( url ) . then ( res => {
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
return res . text ( ) . then ( result => {
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should make capitalised Content-Encoding lowercase' , ( ) => {
const url = ` ${ base } gzip-capital ` ;
return fetch ( url ) . then ( res => {
expect ( res . headers . get ( 'content-encoding' ) ) . to . equal ( 'gzip' ) ;
return res . text ( ) . then ( result => {
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
it ( 'should decompress deflate response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } deflate ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should decompress deflate raw response from old apache server' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } deflate-raw ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2016-08-03 02:31:46 -07:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2016-08-03 02:31:46 -07:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should decompress brotli response' , function ( ) {
if ( typeof zlib . createBrotliDecompress !== 'function' ) {
this . skip ( ) ;
}
2019-04-26 09:20:15 -07:00
const url = ` ${ base } brotli ` ;
return fetch ( url ) . then ( res => {
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
return res . text ( ) . then ( result => {
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle no content response with brotli encoding' , function ( ) {
if ( typeof zlib . createBrotliDecompress !== 'function' ) {
this . skip ( ) ;
}
2019-04-26 09:20:15 -07:00
const url = ` ${ base } no-content/brotli ` ;
return fetch ( url ) . then ( res => {
expect ( res . status ) . to . equal ( 204 ) ;
expect ( res . statusText ) . to . equal ( 'No Content' ) ;
expect ( res . headers . get ( 'content-encoding' ) ) . to . equal ( 'br' ) ;
expect ( res . ok ) . to . be . true ;
return res . text ( ) . then ( result => {
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . be . empty ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should skip decompression if unsupported' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } sdch ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 21:01:10 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 21:01:10 -08:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . equal ( 'fake sdch string' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject if response compression is invalid' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } invalid-content-encoding ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-09-28 06:58:45 -07:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-04-05 06:20:42 -07:00
return expect ( res . text ( ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'code' , 'Z_DATA_ERROR' ) ;
2015-09-28 06:58:45 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should handle errors on the body stream even if it is not used' , done => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } invalid-content-encoding ` ;
2018-01-27 11:20:05 -08:00
fetch ( url )
. then ( res => {
expect ( res . status ) . to . equal ( 200 ) ;
} )
2020-03-13 08:06:25 -07:00
. catch ( ( ) => { } )
2018-01-27 11:20:05 -08:00
. then ( ( ) => {
// Wait a few ms to see if a uncaught error occurs
setTimeout ( ( ) => {
done ( ) ;
2019-05-15 23:38:28 -07:00
} , 20 ) ;
2018-01-27 11:20:05 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should collect handled errors on the body stream to reject if the body is used later' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } invalid-content-encoding ` ;
2020-05-22 12:19:05 -07:00
return fetch ( url ) . then ( delay ( 20 ) ) . then ( res => {
2018-01-27 11:20:05 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
return expect ( res . text ( ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'code' , 'Z_DATA_ERROR' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow disabling auto decompression' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } gzip ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-27 07:33:06 -08:00
compress : false
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-10-10 11:50:04 -07:00
return res . text ( ) . then ( result => {
2015-01-27 07:33:06 -08:00
expect ( result ) . to . be . a ( 'string' ) ;
expect ( result ) . to . not . equal ( 'hello world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should not overwrite existing accept-encoding header when auto decompression is true' , ( ) => {
2018-11-05 01:42:51 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-11-05 01:42:51 -08:00
compress : true ,
headers : {
'Accept-Encoding' : 'gzip'
}
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-11-05 01:42:51 -08:00
expect ( res . headers [ 'accept-encoding' ] ) . to . equal ( 'gzip' ) ;
} ) ;
} ) ;
2021-03-04 07:01:38 -08:00
const testAbortController = ( name , buildAbortController , moreTests = null ) => {
describe ( ` AbortController ( ${ name } ) ` , ( ) => {
let controller ;
2018-11-12 20:40:11 -08:00
2021-03-04 07:01:38 -08:00
beforeEach ( ( ) => {
controller = buildAbortController ( ) ;
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
it ( 'should support request cancellation with signal' , ( ) => {
const fetches = [
fetch (
` ${ base } timeout ` ,
{
method : 'POST' ,
signal : controller . signal ,
headers : {
'Content-Type' : 'application/json' ,
body : JSON . stringify ( { hello : 'world' } )
}
}
)
] ;
setTimeout ( ( ) => {
controller . abort ( ) ;
} , 100 ) ;
return Promise . all ( fetches . map ( fetched => expect ( fetched )
. to . eventually . be . rejected
. and . be . an . instanceOf ( Error )
. and . include ( {
type : 'aborted' ,
name : 'AbortError'
} )
) ) ;
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
it ( 'should support multiple request cancellation with signal' , ( ) => {
const fetches = [
fetch ( ` ${ base } timeout ` , { signal : controller . signal } ) ,
fetch (
` ${ base } timeout ` ,
{
method : 'POST' ,
signal : controller . signal ,
headers : {
'Content-Type' : 'application/json' ,
body : JSON . stringify ( { hello : 'world' } )
}
}
)
] ;
setTimeout ( ( ) => {
controller . abort ( ) ;
} , 100 ) ;
2018-11-12 20:40:11 -08:00
2021-03-04 07:01:38 -08:00
return Promise . all ( fetches . map ( fetched => expect ( fetched )
2018-11-12 20:40:11 -08:00
. to . eventually . be . rejected
2021-03-04 07:01:38 -08:00
. and . be . an . instanceOf ( Error )
. and . include ( {
type : 'aborted' ,
name : 'AbortError'
} )
) ) ;
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
it ( 'should reject immediately if signal has already been aborted' , ( ) => {
const url = ` ${ base } timeout ` ;
const options = {
signal : controller . signal
} ;
2018-11-12 20:40:11 -08:00
controller . abort ( ) ;
2021-03-04 07:01:38 -08:00
const fetched = fetch ( url , options ) ;
return expect ( fetched ) . to . eventually . be . rejected
. and . be . an . instanceOf ( Error )
. and . include ( {
type : 'aborted' ,
name : 'AbortError'
} ) ;
} ) ;
it ( 'should allow redirects to be aborted' , ( ) => {
const request = new Request ( ` ${ base } redirect/slow ` , {
signal : controller . signal
} ) ;
setTimeout ( ( ) => {
controller . abort ( ) ;
} , 20 ) ;
return expect ( fetch ( request ) ) . to . be . eventually . rejected
. and . be . an . instanceOf ( Error )
2018-11-12 20:40:11 -08:00
. and . have . property ( 'name' , 'AbortError' ) ;
} ) ;
2021-03-04 07:01:38 -08:00
it ( 'should allow redirected response body to be aborted' , ( ) => {
const request = new Request ( ` ${ base } redirect/slow-stream ` , {
signal : controller . signal
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
return expect ( fetch ( request ) . then ( res => {
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
const result = res . text ( ) ;
controller . abort ( ) ;
return result ;
} ) ) . to . be . eventually . rejected
. and . be . an . instanceOf ( Error )
. and . have . property ( 'name' , 'AbortError' ) ;
} ) ;
it ( 'should reject response body with AbortError when aborted before stream has been read completely' , ( ) => {
return expect ( fetch (
` ${ base } slow ` ,
{ signal : controller . signal }
) )
. to . eventually . be . fulfilled
. then ( res => {
const promise = res . text ( ) ;
controller . abort ( ) ;
return expect ( promise )
. to . eventually . be . rejected
. and . be . an . instanceof ( Error )
. and . have . property ( 'name' , 'AbortError' ) ;
} ) ;
} ) ;
it ( 'should reject response body methods immediately with AbortError when aborted before stream is disturbed' , ( ) => {
return expect ( fetch (
` ${ base } slow ` ,
{ signal : controller . signal }
) )
. to . eventually . be . fulfilled
. then ( res => {
controller . abort ( ) ;
return expect ( res . text ( ) )
. to . eventually . be . rejected
. and . be . an . instanceof ( Error )
. and . have . property ( 'name' , 'AbortError' ) ;
} ) ;
} ) ;
it ( 'should emit error event to response body with an AbortError when aborted before underlying stream is closed' , done => {
expect ( fetch (
` ${ base } slow ` ,
{ signal : controller . signal }
) )
. to . eventually . be . fulfilled
. then ( res => {
res . body . once ( 'error' , err => {
expect ( err )
. to . be . an . instanceof ( Error )
. and . have . property ( 'name' , 'AbortError' ) ;
done ( ) ;
} ) ;
controller . abort ( ) ;
} ) ;
} ) ;
it ( 'should cancel request body of type Stream with AbortError when aborted' , ( ) => {
const body = new stream . Readable ( { objectMode : true } ) ;
body . _read = ( ) => { } ;
const promise = fetch (
` ${ base } slow ` ,
{ signal : controller . signal , body , method : 'POST' }
) ;
const result = Promise . all ( [
new Promise ( ( resolve , reject ) => {
body . on ( 'error' , error => {
try {
expect ( error ) . to . be . an . instanceof ( Error ) . and . have . property ( 'name' , 'AbortError' ) ;
resolve ( ) ;
} catch ( error _ ) {
reject ( error _ ) ;
}
} ) ;
} ) ,
expect ( promise ) . to . eventually . be . rejected
. and . be . an . instanceof ( Error )
. and . have . property ( 'name' , 'AbortError' )
] ) ;
2018-11-12 20:40:11 -08:00
controller . abort ( ) ;
2021-03-04 07:01:38 -08:00
return result ;
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
if ( moreTests ) {
moreTests ( ) ;
}
} ) ;
} ;
testAbortController ( 'polyfill' ,
( ) => new AbortControllerPolyfill ( ) ,
( ) => {
it ( 'should remove internal AbortSignal event listener after request is aborted' , ( ) => {
const controller = new AbortControllerPolyfill ( ) ;
const { signal } = controller ;
setTimeout ( ( ) => {
controller . abort ( ) ;
} , 20 ) ;
return expect ( fetch ( ` ${ base } timeout ` , { signal } ) )
. to . eventually . be . rejected
. and . be . an . instanceof ( Error )
. and . have . property ( 'name' , 'AbortError' )
. then ( ( ) => {
return expect ( signal . listeners . abort . length ) . to . equal ( 0 ) ;
} ) ;
} ) ;
it ( 'should remove internal AbortSignal event listener after request and response complete without aborting' , ( ) => {
const controller = new AbortControllerPolyfill ( ) ;
const { signal } = controller ;
const fetchHtml = fetch ( ` ${ base } html ` , { signal } )
. then ( res => res . text ( ) ) ;
const fetchResponseError = fetch ( ` ${ base } error/reset ` , { signal } ) ;
const fetchRedirect = fetch ( ` ${ base } redirect/301 ` , { signal } ) . then ( res => res . json ( ) ) ;
return Promise . all ( [
expect ( fetchHtml ) . to . eventually . be . fulfilled . and . equal ( '<html></html>' ) ,
expect ( fetchResponseError ) . to . be . eventually . rejected ,
expect ( fetchRedirect ) . to . eventually . be . fulfilled
] ) . then ( ( ) => {
expect ( signal . listeners . abort . length ) . to . equal ( 0 ) ;
2018-11-12 20:40:11 -08:00
} ) ;
2021-03-04 07:01:38 -08:00
} ) ;
}
) ;
2018-11-12 20:40:11 -08:00
2021-03-04 07:01:38 -08:00
testAbortController ( 'mysticatea' , ( ) => new AbortControllerMysticatea ( ) ) ;
2018-11-12 20:40:11 -08:00
2021-03-04 07:01:38 -08:00
if ( process . version > 'v15' ) {
testAbortController ( 'native' , ( ) => new AbortController ( ) ) ;
}
2018-11-12 20:40:11 -08:00
2020-12-31 21:37:26 -08:00
it ( 'should throw a TypeError if a signal is not of type AbortSignal or EventTarget' , ( ) => {
2018-11-12 20:40:11 -08:00
return Promise . all ( [
2020-03-13 08:06:25 -07:00
expect ( fetch ( ` ${ base } inspect ` , { signal : { } } ) )
2018-11-12 20:40:11 -08:00
. to . be . eventually . rejected
. and . be . an . instanceof ( TypeError )
. and . have . property ( 'message' ) . includes ( 'AbortSignal' ) ,
2020-03-13 08:06:25 -07:00
expect ( fetch ( ` ${ base } inspect ` , { signal : '' } ) )
2018-11-12 20:40:11 -08:00
. to . be . eventually . rejected
. and . be . an . instanceof ( TypeError )
. and . have . property ( 'message' ) . includes ( 'AbortSignal' ) ,
2020-03-13 08:06:25 -07:00
expect ( fetch ( ` ${ base } inspect ` , { signal : Object . create ( null ) } ) )
2018-11-12 20:40:11 -08:00
. to . be . eventually . rejected
. and . be . an . instanceof ( TypeError )
2020-03-13 08:06:25 -07:00
. and . have . property ( 'message' ) . includes ( 'AbortSignal' )
2018-11-12 20:40:11 -08:00
] ) ;
} ) ;
2020-12-31 21:35:46 -08:00
it ( 'should gracefully handle a nullish signal' , ( ) => {
return Promise . all ( [
fetch ( ` ${ base } hello ` , { signal : null } ) . then ( res => {
return expect ( res . ok ) . to . be . true ;
} ) ,
fetch ( ` ${ base } hello ` , { signal : undefined } ) . then ( res => {
return expect ( res . ok ) . to . be . true ;
} )
] ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should set default User-Agent' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2018-11-05 01:42:51 -08:00
return fetch ( url ) . then ( res => res . json ( ) ) . then ( res => {
2020-03-13 08:06:25 -07:00
expect ( res . headers [ 'user-agent' ] ) . to . startWith ( 'node-fetch' ) ;
2016-12-05 19:35:23 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow setting User-Agent' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-12-05 19:35:23 -08:00
headers : {
'user-agent' : 'faked'
}
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'user-agent' ] ) . to . equal ( 'faked' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should set default Accept header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2016-12-05 19:35:23 -08:00
fetch ( url ) . then ( res => res . json ( ) ) . then ( res => {
expect ( res . headers . accept ) . to . equal ( '*/*' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow setting Accept header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-12-05 19:35:23 -08:00
headers : {
2020-03-13 08:06:25 -07:00
accept : 'application/json'
2016-12-05 19:35:23 -08:00
}
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2016-12-05 19:35:23 -08:00
expect ( res . headers . accept ) . to . equal ( 'application/json' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-27 07:33:06 -08:00
method : 'POST'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 07:33:06 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . method ) . to . equal ( 'POST' ) ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'content-length' ] ) . to . equal ( '0' ) ;
2015-01-27 07:33:06 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with string body' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : 'a=1'
2015-01-27 07:33:06 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 07:33:06 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'text/plain;charset=UTF-8' ) ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
2015-01-27 07:33:06 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with buffer body' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : Buffer . from ( 'a=1' , 'utf-8' )
2016-08-02 22:07:47 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-08-02 22:07:47 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2016-08-02 22:07:47 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
2016-12-05 20:30:00 -08:00
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
2016-12-05 20:30:00 -08:00
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
2016-08-02 22:07:47 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBuffer body' , ( ) => {
2020-06-13 00:13:50 -07:00
const encoder = new TextEncoder ( ) ;
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
2020-06-13 00:13:50 -07:00
body : encoder . encode ( 'Hello, world!\n' ) . buffer
2018-03-04 16:40:39 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-03-04 16:40:39 -08:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'Hello, world!\n' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '14' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBuffer body from a VM context' , ( ) => {
2018-07-21 22:13:01 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-07-21 22:13:01 -07:00
method : 'POST' ,
body : new VMUint8Array ( Buffer . from ( 'Hello, world!\n' ) ) . buffer
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-07-21 22:13:01 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'Hello, world!\n' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '14' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBufferView (Uint8Array) body' , ( ) => {
2020-06-13 00:13:50 -07:00
const encoder = new TextEncoder ( ) ;
2018-05-27 20:18:17 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-05-27 20:18:17 -07:00
method : 'POST' ,
2020-06-13 00:13:50 -07:00
body : encoder . encode ( 'Hello, world!\n' )
2018-05-27 20:18:17 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-05-27 20:18:17 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'Hello, world!\n' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '14' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBufferView (DataView) body' , ( ) => {
2020-06-13 00:13:50 -07:00
const encoder = new TextEncoder ( ) ;
2018-05-27 20:18:17 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-05-27 20:18:17 -07:00
method : 'POST' ,
2020-06-13 00:13:50 -07:00
body : new DataView ( encoder . encode ( 'Hello, world!\n' ) . buffer )
2018-05-27 20:18:17 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-05-27 20:18:17 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'Hello, world!\n' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '14' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBufferView (Uint8Array) body from a VM context' , ( ) => {
2018-07-21 22:13:01 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-07-21 22:13:01 -07:00
method : 'POST' ,
body : new VMUint8Array ( Buffer . from ( 'Hello, world!\n' ) )
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-07-21 22:13:01 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'Hello, world!\n' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '14' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with ArrayBufferView (Uint8Array, offset, length) body' , ( ) => {
2020-06-13 00:13:50 -07:00
const encoder = new TextEncoder ( ) ;
2018-05-27 20:18:17 -07:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-05-27 20:18:17 -07:00
method : 'POST' ,
2020-06-13 00:13:50 -07:00
body : encoder . encode ( 'Hello, world!\n' ) . subarray ( 7 , 13 )
2018-05-27 20:18:17 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
2018-05-27 20:18:17 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'world!' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '6' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with blob body without type' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : new Blob ( [ 'a=1' ] )
2016-12-05 21:09:54 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-12-05 21:09:54 -08:00
return res . json ( ) ;
} ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with blob body with type' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-12-05 21:09:54 -08:00
method : 'POST' ,
body : new Blob ( [ 'a=1' ] , {
type : 'text/plain;charset=UTF-8'
} )
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-12-05 21:09:54 -08:00
return res . json ( ) ;
} ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'text/plain;charset=utf-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with readable stream as body' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
2020-06-10 04:16:51 -07:00
body : stream . Readable . from ( 'a=1' )
2015-01-27 07:33:06 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 07:33:06 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-01-27 07:33:06 -08:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'transfer-encoding' ] ) . to . equal ( 'chunked' ) ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . be . undefined ;
2015-09-28 02:40:58 -07:00
expect ( res . headers [ 'content-length' ] ) . to . be . undefined ;
2015-01-26 02:15:07 -08:00
} ) ;
} ) ;
2015-01-26 05:58:52 -08:00
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with form-data as body' , ( ) => {
2016-10-10 11:50:04 -07:00
const form = new FormData ( ) ;
2020-03-13 08:06:25 -07:00
form . append ( 'a' , '1' ) ;
2015-07-21 19:05:06 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } multipart ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : form
2015-07-21 19:05:06 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-07-21 19:05:06 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-07-21 19:05:06 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . startWith ( 'multipart/form-data;boundary=' ) ;
2016-03-19 00:51:48 -07:00
expect ( res . headers [ 'content-length' ] ) . to . be . a ( 'string' ) ;
2015-07-22 00:40:52 -07:00
expect ( res . body ) . to . equal ( 'a=1' ) ;
2015-07-21 19:05:06 -07:00
} ) ;
} ) ;
2020-06-10 13:31:35 -07:00
it ( 'should allow POST request with form-data using stream as body' , ( ) => {
2016-10-10 11:50:04 -07:00
const form = new FormData ( ) ;
2020-05-20 23:50:31 -07:00
form . append ( 'my_field' , fs . createReadStream ( 'test/utils/dummy.txt' ) ) ;
2016-05-25 10:37:36 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } multipart ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : form
2016-05-25 10:37:36 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-05-25 10:37:36 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2016-05-25 10:37:36 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . startWith ( 'multipart/form-data;boundary=' ) ;
2016-05-25 10:37:36 -07:00
expect ( res . headers [ 'content-length' ] ) . to . be . undefined ;
expect ( res . body ) . to . contain ( 'my_field=' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with form-data as body and custom headers' , ( ) => {
2016-10-10 11:50:04 -07:00
const form = new FormData ( ) ;
2020-03-13 08:06:25 -07:00
form . append ( 'a' , '1' ) ;
2015-07-22 00:40:52 -07:00
2016-10-10 11:50:04 -07:00
const headers = form . getHeaders ( ) ;
2020-03-13 08:06:25 -07:00
headers . b = '2' ;
2015-07-22 00:40:52 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } multipart ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
body : form ,
headers
2015-07-22 00:40:52 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-07-22 00:40:52 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-07-22 00:40:52 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
2016-12-05 19:35:23 -08:00
expect ( res . headers [ 'content-type' ] ) . to . startWith ( 'multipart/form-data; boundary=' ) ;
2016-03-19 00:51:48 -07:00
expect ( res . headers [ 'content-length' ] ) . to . be . a ( 'string' ) ;
2015-07-22 00:40:52 -07:00
expect ( res . headers . b ) . to . equal ( '2' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
2015-07-21 19:05:06 -07:00
2020-06-10 13:31:35 -07:00
it ( 'should support spec-compliant form-data as POST body' , ( ) => {
const form = new FormDataNode ( ) ;
const filename = path . join ( 'test' , 'utils' , 'dummy.txt' ) ;
form . set ( 'field' , 'some text' ) ;
form . set ( 'file' , fs . createReadStream ( filename ) , {
size : fs . statSync ( filename ) . size
} ) ;
const url = ` ${ base } multipart ` ;
const options = {
method : 'POST' ,
body : form
} ;
return fetch ( url , options ) . then ( res => res . json ( ) ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . headers [ 'content-type' ] ) . to . startWith ( 'multipart/form-data' ) ;
expect ( res . body ) . to . contain ( 'field=' ) ;
expect ( res . body ) . to . contain ( 'file=' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with object body' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
// Note that fetch simply calls tostring on an object
const options = {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
2020-03-13 08:06:25 -07:00
body : { a : 1 }
2016-09-11 07:33:22 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-09-11 07:33:22 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2016-09-11 07:33:22 -07:00
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . body ) . to . equal ( '[object Object]' ) ;
2016-12-05 20:25:13 -08:00
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'text/plain;charset=UTF-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '15' ) ;
2016-09-11 07:33:22 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'constructing a Response with URLSearchParams as body should have a Content-Type' , ( ) => {
const parameters = new URLSearchParams ( ) ;
const res = new Response ( parameters ) ;
2018-11-13 08:36:44 -08:00
res . headers . get ( 'Content-Type' ) ;
expect ( res . headers . get ( 'Content-Type' ) ) . to . equal ( 'application/x-www-form-urlencoded;charset=UTF-8' ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'constructing a Request with URLSearchParams as body should have a Content-Type' , ( ) => {
const parameters = new URLSearchParams ( ) ;
const request = new Request ( base , { method : 'POST' , body : parameters } ) ;
expect ( request . headers . get ( 'Content-Type' ) ) . to . equal ( 'application/x-www-form-urlencoded;charset=UTF-8' ) ;
2018-11-13 08:36:44 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'Reading a body with URLSearchParams should echo back the result' , ( ) => {
const parameters = new URLSearchParams ( ) ;
parameters . append ( 'a' , '1' ) ;
return new Response ( parameters ) . text ( ) . then ( text => {
2018-11-13 08:36:44 -08:00
expect ( text ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
// Body should been cloned...
2020-03-13 08:06:25 -07:00
it ( 'constructing a Request/Response with URLSearchParams and mutating it should not affected body' , ( ) => {
const parameters = new URLSearchParams ( ) ;
const request = new Request ( ` ${ base } inspect ` , { method : 'POST' , body : parameters } ) ;
parameters . append ( 'a' , '1' ) ;
return request . text ( ) . then ( text => {
2018-11-13 08:36:44 -08:00
expect ( text ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow POST request with URLSearchParams as body' , ( ) => {
const parameters = new URLSearchParams ( ) ;
parameters . append ( 'a' , '1' ) ;
2017-06-11 22:29:50 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2017-06-11 22:29:50 -07:00
method : 'POST' ,
2020-03-13 08:06:25 -07:00
body : parameters
2017-06-11 22:29:50 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2017-06-11 22:29:50 -07:00
return res . json ( ) ;
} ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'application/x-www-form-urlencoded;charset=UTF-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should still recognize URLSearchParams when extended' , ( ) => {
class CustomSearchParameters extends URLSearchParams { }
const parameters = new CustomSearchParameters ( ) ;
parameters . append ( 'a' , '1' ) ;
2017-06-11 22:29:50 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2017-06-11 22:29:50 -07:00
method : 'POST' ,
2020-03-13 08:06:25 -07:00
body : parameters
2017-06-11 22:29:50 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2017-06-11 22:29:50 -07:00
return res . json ( ) ;
} ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'application/x-www-form-urlencoded;charset=UTF-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
/ * F o r 1 0 0 % c o d e c o v e r a g e , c h e c k s f o r d u c k - t y p i n g - o n l y d e t e c t i o n
2017-06-11 22:29:50 -07:00
* where both constructor . name and brand tests fail * /
2020-03-13 08:06:25 -07:00
it ( 'should still recognize URLSearchParams when extended from polyfill' , ( ) => {
class CustomPolyfilledSearchParameters extends URLSearchParams { }
const parameters = new CustomPolyfilledSearchParameters ( ) ;
parameters . append ( 'a' , '1' ) ;
2017-06-11 22:29:50 -07:00
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2017-06-11 22:29:50 -07:00
method : 'POST' ,
2020-03-13 08:06:25 -07:00
body : parameters
2017-06-11 22:29:50 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2017-06-11 22:29:50 -07:00
return res . json ( ) ;
} ) . then ( res => {
expect ( res . method ) . to . equal ( 'POST' ) ;
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'application/x-www-form-urlencoded;charset=UTF-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should overwrite Content-Length if possible' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
// Note that fetch simply calls tostring on an object
const options = {
2017-01-29 09:56:19 -08:00
method : 'POST' ,
headers : {
'Content-Length' : '1000'
} ,
body : 'a=1'
2015-01-27 09:00:53 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 09:00:53 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2017-01-29 09:56:19 -08:00
expect ( res . method ) . to . equal ( 'POST' ) ;
2015-01-27 09:00:53 -08:00
expect ( res . body ) . to . equal ( 'a=1' ) ;
2017-01-29 09:56:19 -08:00
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-type' ] ) . to . equal ( 'text/plain;charset=UTF-8' ) ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
2015-01-27 09:00:53 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow PUT request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PUT' ,
body : 'a=1'
2015-01-27 09:00:53 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 09:00:53 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2017-01-29 09:56:19 -08:00
expect ( res . method ) . to . equal ( 'PUT' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
2016-05-25 11:00:25 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow DELETE request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2017-01-29 09:56:19 -08:00
method : 'DELETE'
2016-05-25 11:00:25 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-05-25 11:00:25 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2017-01-29 09:56:19 -08:00
expect ( res . method ) . to . equal ( 'DELETE' ) ;
2016-05-25 11:00:25 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow DELETE request with string body' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'DELETE' ,
body : 'a=1'
2016-05-25 11:00:25 -07:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-05-25 11:00:25 -07:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2016-05-25 11:00:25 -07:00
expect ( res . method ) . to . equal ( 'DELETE' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
expect ( res . headers [ 'transfer-encoding' ] ) . to . be . undefined ;
expect ( res . headers [ 'content-length' ] ) . to . equal ( '3' ) ;
2015-01-27 09:00:53 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow PATCH request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-03-04 20:29:12 -08:00
method : 'PATCH' ,
body : 'a=1'
2015-01-27 21:01:10 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 21:01:10 -08:00
return res . json ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( res => {
2015-01-27 21:01:10 -08:00
expect ( res . method ) . to . equal ( 'PATCH' ) ;
expect ( res . body ) . to . equal ( 'a=1' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow HEAD request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-27 09:00:53 -08:00
method : 'HEAD'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 09:00:53 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . statusText ) . to . equal ( 'OK' ) ;
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
expect ( res . body ) . to . be . an . instanceof ( stream . Transform ) ;
2016-08-02 21:55:58 -07:00
return res . text ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( text => {
2016-08-02 21:55:58 -07:00
expect ( text ) . to . equal ( '' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow HEAD request with content-encoding header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } error/404 ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-08-02 21:55:58 -07:00
method : 'HEAD'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-08-02 21:55:58 -07:00
expect ( res . status ) . to . equal ( 404 ) ;
expect ( res . headers . get ( 'content-encoding' ) ) . to . equal ( 'gzip' ) ;
return res . text ( ) ;
2016-10-10 11:50:04 -07:00
} ) . then ( text => {
2016-08-02 21:55:58 -07:00
expect ( text ) . to . equal ( '' ) ;
2015-01-27 09:00:53 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow OPTIONS request' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } options ` ;
2020-03-13 08:06:25 -07:00
const options = {
2016-03-19 03:24:08 -07:00
method : 'OPTIONS'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2016-03-19 03:24:08 -07:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . statusText ) . to . equal ( 'OK' ) ;
expect ( res . headers . get ( 'allow' ) ) . to . equal ( 'GET, HEAD, OPTIONS' ) ;
expect ( res . body ) . to . be . an . instanceof ( stream . Transform ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should reject decoding body twice' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } plain ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2015-01-27 09:00:53 -08:00
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2020-03-13 08:06:25 -07:00
return res . text ( ) . then ( ( ) => {
2015-01-27 09:00:53 -08:00
expect ( res . bodyUsed ) . to . be . true ;
return expect ( res . text ( ) ) . to . eventually . be . rejectedWith ( Error ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support maximum response size, multiple chunk' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } size/chunk ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-28 06:56:25 -08:00
size : 5
2015-01-27 09:00:53 -08:00
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-27 09:00:53 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-04-05 06:20:42 -07:00
return expect ( res . text ( ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'max-size' ) ;
2015-01-27 09:00:53 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support maximum response size, single chunk' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } size/long ` ;
2020-03-13 08:06:25 -07:00
const options = {
2015-01-28 06:56:25 -08:00
size : 5
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2015-01-28 06:56:25 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . headers . get ( 'content-type' ) ) . to . equal ( 'text/plain' ) ;
2016-04-05 06:20:42 -07:00
return expect ( res . text ( ) ) . to . eventually . be . rejected
. and . be . an . instanceOf ( FetchError )
. and . have . property ( 'type' , 'max-size' ) ;
2015-01-28 06:56:25 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow piping response body as stream' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2016-11-23 11:30:01 -08:00
return fetch ( url ) . then ( res => {
2015-01-27 21:01:10 -08:00
expect ( res . body ) . to . be . an . instanceof ( stream . Transform ) ;
2016-11-23 11:30:01 -08:00
return streamToPromise ( res . body , chunk => {
2015-01-27 21:01:10 -08:00
if ( chunk === null ) {
return ;
}
2020-03-13 08:06:25 -07:00
2015-01-27 21:01:10 -08:00
expect ( chunk . toString ( ) ) . to . equal ( 'world' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow cloning a response, and use both as stream' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
const r1 = res . clone ( ) ;
2016-03-19 03:06:33 -07:00
expect ( res . body ) . to . be . an . instanceof ( stream . Transform ) ;
expect ( r1 . body ) . to . be . an . instanceof ( stream . Transform ) ;
2016-11-23 11:30:01 -08:00
const dataHandler = chunk => {
2016-03-19 03:06:33 -07:00
if ( chunk === null ) {
return ;
}
2020-03-13 08:06:25 -07:00
2016-03-19 03:06:33 -07:00
expect ( chunk . toString ( ) ) . to . equal ( 'world' ) ;
2016-11-23 11:30:01 -08:00
} ;
return Promise . all ( [
streamToPromise ( res . body , dataHandler ) ,
streamToPromise ( r1 . body , dataHandler )
] ) ;
2016-03-19 03:06:33 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow cloning a json response and log it as text response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } json ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
const r1 = res . clone ( ) ;
2017-02-26 14:42:46 -08:00
return Promise . all ( [ res . json ( ) , r1 . text ( ) ] ) . then ( results => {
2016-03-23 00:23:56 -07:00
expect ( results [ 0 ] ) . to . deep . equal ( { name : 'value' } ) ;
expect ( results [ 1 ] ) . to . equal ( '{"name":"value"}' ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow cloning a json response, and then log it as text response' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } json ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
const r1 = res . clone ( ) ;
return res . json ( ) . then ( result => {
2016-03-23 00:23:56 -07:00
expect ( result ) . to . deep . equal ( { name : 'value' } ) ;
2016-10-10 11:50:04 -07:00
return r1 . text ( ) . then ( result => {
2016-03-23 00:23:56 -07:00
expect ( result ) . to . equal ( '{"name":"value"}' ) ;
} ) ;
2016-03-19 03:06:33 -07:00
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow cloning a json response, first log as text response, then return json object' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } json ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
const r1 = res . clone ( ) ;
return r1 . text ( ) . then ( result => {
2016-05-25 10:01:56 -07:00
expect ( result ) . to . equal ( '{"name":"value"}' ) ;
2016-10-10 11:50:04 -07:00
return res . json ( ) . then ( result => {
2016-05-25 10:01:56 -07:00
expect ( result ) . to . deep . equal ( { name : 'value' } ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should not allow cloning a response after its been used' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res =>
2020-03-13 08:06:25 -07:00
res . text ( ) . then ( ( ) => {
2016-10-10 11:50:04 -07:00
expect ( ( ) => {
res . clone ( ) ;
2016-03-19 03:06:33 -07:00
} ) . to . throw ( Error ) ;
2016-10-10 11:50:04 -07:00
} )
) ;
2016-03-19 03:06:33 -07:00
} ) ;
2020-05-24 03:16:34 -07:00
it ( 'the default highWaterMark should equal 16384' , ( ) => {
const url = ` ${ base } hello ` ;
return fetch ( url ) . then ( res => {
expect ( res . highWaterMark ) . to . equal ( 16384 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should timeout on cloning response without consuming one of the streams when the second packet size is equal default highWaterMark' , function ( ) {
this . timeout ( 300 ) ;
const url = local . mockResponse ( res => {
// Observed behavior of TCP packets splitting:
// - response body size <= 65438 → single packet sent
// - response body size > 65438 → multiple packets sent
// Max TCP packet size is 64kB (https://stackoverflow.com/a/2614188/5763764),
// but first packet probably transfers more than the response body.
const firstPacketMaxSize = 65438 ;
const secondPacketSize = 16 * 1024 ; // = defaultHighWaterMark
res . end ( crypto . randomBytes ( firstPacketMaxSize + secondPacketSize ) ) ;
} ) ;
return expect (
fetch ( url ) . then ( res => res . clone ( ) . buffer ( ) )
) . to . timeout ;
} ) ;
it ( 'should timeout on cloning response without consuming one of the streams when the second packet size is equal custom highWaterMark' , function ( ) {
this . timeout ( 300 ) ;
const url = local . mockResponse ( res => {
const firstPacketMaxSize = 65438 ;
const secondPacketSize = 10 ;
res . end ( crypto . randomBytes ( firstPacketMaxSize + secondPacketSize ) ) ;
} ) ;
return expect (
fetch ( url , { highWaterMark : 10 } ) . then ( res => res . clone ( ) . buffer ( ) )
) . to . timeout ;
} ) ;
it ( 'should not timeout on cloning response without consuming one of the streams when the second packet size is less than default highWaterMark' , function ( ) {
this . timeout ( 300 ) ;
const url = local . mockResponse ( res => {
const firstPacketMaxSize = 65438 ;
const secondPacketSize = 16 * 1024 ; // = defaultHighWaterMark
res . end ( crypto . randomBytes ( firstPacketMaxSize + secondPacketSize - 1 ) ) ;
} ) ;
return expect (
fetch ( url ) . then ( res => res . clone ( ) . buffer ( ) )
) . not . to . timeout ;
} ) ;
it ( 'should not timeout on cloning response without consuming one of the streams when the second packet size is less than custom highWaterMark' , function ( ) {
this . timeout ( 300 ) ;
const url = local . mockResponse ( res => {
const firstPacketMaxSize = 65438 ;
const secondPacketSize = 10 ;
res . end ( crypto . randomBytes ( firstPacketMaxSize + secondPacketSize - 1 ) ) ;
} ) ;
return expect (
fetch ( url , { highWaterMark : 10 } ) . then ( res => res . clone ( ) . buffer ( ) )
) . not . to . timeout ;
} ) ;
it ( 'should not timeout on cloning response without consuming one of the streams when the response size is double the custom large highWaterMark - 1' , function ( ) {
this . timeout ( 300 ) ;
const url = local . mockResponse ( res => {
2020-05-25 08:11:56 -07:00
res . end ( crypto . randomBytes ( ( 2 * 512 * 1024 ) - 1 ) ) ;
2020-03-13 08:06:25 -07:00
} ) ;
return expect (
fetch ( url , { highWaterMark : 512 * 1024 } ) . then ( res => res . clone ( ) . buffer ( ) )
) . not . to . timeout ;
} ) ;
it ( 'should allow get all responses of a header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } cookie ` ;
2016-10-10 11:50:04 -07:00
return fetch ( url ) . then ( res => {
2017-04-02 08:43:46 -07:00
const expected = 'a=1, b=1' ;
2016-10-10 18:31:53 -07:00
expect ( res . headers . get ( 'set-cookie' ) ) . to . equal ( expected ) ;
expect ( res . headers . get ( 'Set-Cookie' ) ) . to . equal ( expected ) ;
2015-01-27 09:00:53 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should return all headers using raw()' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } cookie ` ;
2017-03-20 09:22:49 -07:00
return fetch ( url ) . then ( res => {
const expected = [
'a=1' ,
'b=1'
] ;
expect ( res . headers . raw ( ) [ 'set-cookie' ] ) . to . deep . equal ( expected ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should allow deleting header' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } cookie ` ;
2018-02-03 11:57:27 -08:00
return fetch ( url ) . then ( res => {
res . headers . delete ( 'set-cookie' ) ;
expect ( res . headers . get ( 'set-cookie' ) ) . to . be . null ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should send request with connection keep-alive if agent is provided' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const options = {
2018-02-03 11:57:27 -08:00
agent : new http . Agent ( {
keepAlive : true
} )
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-02-03 11:57:27 -08:00
return res . json ( ) ;
} ) . then ( res => {
2020-03-13 08:06:25 -07:00
expect ( res . headers . connection ) . to . equal ( 'keep-alive' ) ;
2018-02-03 11:57:27 -08:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support fetch with Request instance' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2020-03-13 08:06:25 -07:00
const request = new Request ( url ) ;
return fetch ( request ) . then ( res => {
2018-02-03 11:57:27 -08:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support fetch with Node.js URL object' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2020-03-13 08:06:25 -07:00
const urlObject = new URL ( url ) ;
const request = new Request ( urlObject ) ;
return fetch ( request ) . then ( res => {
2018-02-03 11:57:27 -08:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support fetch with WHATWG URL object' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2020-03-13 08:06:25 -07:00
const urlObject = new URL ( url ) ;
const request = new Request ( urlObject ) ;
return fetch ( request ) . then ( res => {
2018-02-03 11:57:27 -08:00
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-04-20 12:42:51 -07:00
it ( 'should keep `?` sign in URL when no params are given' , ( ) => {
const url = ` ${ base } question? ` ;
const urlObject = new URL ( url ) ;
const request = new Request ( urlObject ) ;
return fetch ( request ) . then ( res => {
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
it ( 'if params are given, do not modify anything' , ( ) => {
const url = ` ${ base } question?a=1 ` ;
const urlObject = new URL ( url ) ;
const request = new Request ( urlObject ) ;
return fetch ( request ) . then ( res => {
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
it ( 'should preserve the hash (#) symbol' , ( ) => {
const url = ` ${ base } question?# ` ;
const urlObject = new URL ( url ) ;
const request = new Request ( urlObject ) ;
return fetch ( request ) . then ( res => {
expect ( res . url ) . to . equal ( url ) ;
expect ( res . ok ) . to . be . true ;
expect ( res . status ) . to . equal ( 200 ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support reading blob as text' , ( ) => {
return new Response ( 'hello' )
2019-04-15 13:46:11 -07:00
. blob ( )
. then ( blob => blob . text ( ) )
. then ( body => {
expect ( body ) . to . equal ( 'hello' ) ;
2019-04-16 03:29:17 -07:00
} ) ;
} ) ;
2019-04-15 13:46:11 -07:00
2020-03-13 08:06:25 -07:00
it ( 'should support reading blob as arrayBuffer' , ( ) => {
return new Response ( 'hello' )
2019-04-15 13:46:11 -07:00
. blob ( )
. then ( blob => blob . arrayBuffer ( ) )
. then ( ab => {
2020-03-13 08:06:25 -07:00
const string = String . fromCharCode . apply ( null , new Uint8Array ( ab ) ) ;
expect ( string ) . to . equal ( 'hello' ) ;
2019-04-16 03:29:17 -07:00
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support reading blob as stream' , ( ) => {
return new Response ( 'hello' )
2019-04-16 03:29:17 -07:00
. blob ( )
. then ( blob => streamToPromise ( blob . stream ( ) , data => {
2020-03-13 08:06:25 -07:00
const string = data . toString ( ) ;
expect ( string ) . to . equal ( 'hello' ) ;
2019-04-16 03:29:17 -07:00
} ) ) ;
} ) ;
2019-04-15 13:46:11 -07:00
2020-03-13 08:06:25 -07:00
it ( 'should support blob round-trip' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } hello ` ;
2018-02-03 11:57:27 -08:00
2020-03-13 08:06:25 -07:00
let length ;
let type ;
2018-02-03 11:57:27 -08:00
return fetch ( url ) . then ( res => res . blob ( ) ) . then ( blob => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2018-02-03 11:57:27 -08:00
length = blob . size ;
type = blob . type ;
return fetch ( url , {
method : 'POST' ,
body : blob
} ) ;
} ) . then ( res => res . json ( ) ) . then ( ( { body , headers } ) => {
expect ( body ) . to . equal ( 'world' ) ;
expect ( headers [ 'content-type' ] ) . to . equal ( type ) ;
expect ( headers [ 'content-length' ] ) . to . equal ( String ( length ) ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support overwrite Request instance' , ( ) => {
2018-03-04 20:29:12 -08:00
const url = ` ${ base } inspect ` ;
2020-03-13 08:06:25 -07:00
const request = new Request ( url , {
2018-03-04 20:29:12 -08:00
method : 'POST' ,
headers : {
2018-02-03 11:57:27 -08:00
a : '1'
}
} ) ;
2020-03-13 08:06:25 -07:00
return fetch ( request , {
2018-03-04 20:29:12 -08:00
method : 'GET' ,
headers : {
2018-02-03 11:57:27 -08:00
a : '2'
}
} ) . then ( res => {
return res . json ( ) ;
} ) . then ( body => {
expect ( body . method ) . to . equal ( 'GET' ) ;
expect ( body . headers . a ) . to . equal ( '2' ) ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support arrayBuffer(), blob(), text(), json() and buffer() method in Body constructor' , ( ) => {
2018-02-03 11:57:27 -08:00
const body = new Body ( 'a=1' ) ;
expect ( body ) . to . have . property ( 'arrayBuffer' ) ;
expect ( body ) . to . have . property ( 'blob' ) ;
expect ( body ) . to . have . property ( 'text' ) ;
expect ( body ) . to . have . property ( 'json' ) ;
expect ( body ) . to . have . property ( 'buffer' ) ;
} ) ;
2020-03-13 08:06:25 -07:00
/* eslint-disable-next-line func-names */
2018-02-03 11:57:27 -08:00
it ( 'should create custom FetchError' , function funcName ( ) {
const systemError = new Error ( 'system' ) ;
systemError . code = 'ESOMEERROR' ;
const err = new FetchError ( 'test message' , 'test-error' , systemError ) ;
expect ( err ) . to . be . an . instanceof ( Error ) ;
expect ( err ) . to . be . an . instanceof ( FetchError ) ;
expect ( err . name ) . to . equal ( 'FetchError' ) ;
expect ( err . message ) . to . equal ( 'test message' ) ;
expect ( err . type ) . to . equal ( 'test-error' ) ;
expect ( err . code ) . to . equal ( 'ESOMEERROR' ) ;
expect ( err . errno ) . to . equal ( 'ESOMEERROR' ) ;
2020-03-13 08:06:25 -07:00
// Reading the stack is quite slow (~30-50ms)
2019-05-15 23:38:28 -07:00
expect ( err . stack ) . to . include ( 'funcName' ) . and . to . startWith ( ` ${ err . name } : ${ err . message } ` ) ;
2018-02-03 11:57:27 -08:00
} ) ;
2020-03-13 08:06:25 -07:00
it ( 'should support https request' , function ( ) {
2018-02-03 11:57:27 -08:00
this . timeout ( 5000 ) ;
2018-03-04 20:29:12 -08:00
const url = 'https://github.com/' ;
2020-03-13 08:06:25 -07:00
const options = {
2018-02-03 11:57:27 -08:00
method : 'HEAD'
} ;
2020-03-13 08:06:25 -07:00
return fetch ( url , options ) . then ( res => {
2018-02-03 11:57:27 -08:00
expect ( res . status ) . to . equal ( 200 ) ;
expect ( res . ok ) . to . be . true ;
} ) ;
} ) ;
2020-03-13 08:06:25 -07:00
// Issue #414
it ( 'should reject if attempt to accumulate body stream throws' , ( ) => {
2020-06-10 04:16:51 -07:00
const res = new Response ( stream . Readable . from ( ( async function * ( ) {
yield Buffer . from ( 'tada' ) ;
2020-09-05 05:51:31 -07:00
await new Promise ( resolve => {
setTimeout ( resolve , 200 ) ;
} ) ;
2020-06-10 04:16:51 -07:00
yield { tada : 'yes' } ;
} ) ( ) ) ) ;
2018-03-22 18:38:03 -07:00
2020-06-10 04:16:51 -07:00
return expect ( res . text ( ) ) . to . eventually . be . rejected
2018-03-22 18:38:03 -07:00
. and . be . an . instanceOf ( FetchError )
2020-03-13 08:06:25 -07:00
. and . include ( { type : 'system' } )
2020-06-10 04:16:51 -07:00
. and . have . property ( 'message' ) . that . include ( 'Could not create Buffer' ) ;
2018-03-22 18:38:03 -07:00
} ) ;
2018-06-19 01:50:09 -07:00
2020-03-13 08:06:25 -07:00
it ( 'supports supplying a lookup function to the agent' , ( ) => {
2018-06-19 01:50:09 -07:00
const url = ` ${ base } redirect/301 ` ;
let called = 0 ;
function lookupSpy ( hostname , options , callback ) {
called ++ ;
return lookup ( hostname , options , callback ) ;
}
2020-03-13 08:06:25 -07:00
const agent = http . Agent ( { lookup : lookupSpy } ) ;
return fetch ( url , { agent } ) . then ( ( ) => {
2018-06-19 01:50:09 -07:00
expect ( called ) . to . equal ( 2 ) ;
} ) ;
} ) ;
2018-06-19 10:08:34 -07:00
2020-03-13 08:06:25 -07:00
it ( 'supports supplying a famliy option to the agent' , ( ) => {
2018-06-19 10:08:34 -07:00
const url = ` ${ base } redirect/301 ` ;
const families = [ ] ;
const family = Symbol ( 'family' ) ;
function lookupSpy ( hostname , options , callback ) {
2020-03-13 08:06:25 -07:00
families . push ( options . family ) ;
2018-06-19 10:08:34 -07:00
return lookup ( hostname , { } , callback ) ;
}
2020-03-13 08:06:25 -07:00
const agent = http . Agent ( { lookup : lookupSpy , family } ) ;
return fetch ( url , { agent } ) . then ( ( ) => {
2018-06-19 10:08:34 -07:00
expect ( families ) . to . have . length ( 2 ) ;
expect ( families [ 0 ] ) . to . equal ( family ) ;
expect ( families [ 1 ] ) . to . equal ( family ) ;
} ) ;
} ) ;
2019-05-05 05:12:33 -07:00
2020-03-13 08:06:25 -07:00
it ( 'should allow a function supplying the agent' , ( ) => {
2019-05-05 05:12:33 -07:00
const url = ` ${ base } inspect ` ;
2019-05-15 23:38:28 -07:00
const agent = new http . Agent ( {
2019-05-05 05:12:33 -07:00
keepAlive : true
} ) ;
let parsedURL ;
return fetch ( url , {
2020-03-13 08:06:25 -07:00
agent ( _parsedURL ) {
2019-05-05 05:12:33 -07:00
parsedURL = _parsedURL ;
return agent ;
}
} ) . then ( res => {
return res . json ( ) ;
} ) . then ( res => {
2020-03-13 08:06:25 -07:00
// The agent provider should have been called
2019-05-05 05:12:33 -07:00
expect ( parsedURL . protocol ) . to . equal ( 'http:' ) ;
2020-03-13 08:06:25 -07:00
// The agent we returned should have been used
expect ( res . headers . connection ) . to . equal ( 'keep-alive' ) ;
2019-05-05 05:12:33 -07:00
} ) ;
} ) ;
2019-05-15 23:38:28 -07:00
2020-03-13 08:06:25 -07:00
it ( 'should calculate content length and extract content type for each body type' , ( ) => {
2019-05-15 23:38:28 -07:00
const url = ` ${ base } hello ` ;
const bodyContent = 'a=1' ;
2020-06-10 04:16:51 -07:00
const streamBody = stream . Readable . from ( bodyContent ) ;
2019-05-15 23:38:28 -07:00
const streamRequest = new Request ( url , {
method : 'POST' ,
body : streamBody ,
size : 1024
} ) ;
2020-03-13 08:06:25 -07:00
const blobBody = new Blob ( [ bodyContent ] , { type : 'text/plain' } ) ;
2019-05-15 23:38:28 -07:00
const blobRequest = new Request ( url , {
method : 'POST' ,
body : blobBody ,
size : 1024
} ) ;
2020-03-13 08:06:25 -07:00
const formBody = new FormData ( ) ;
2019-05-15 23:38:28 -07:00
formBody . append ( 'a' , '1' ) ;
const formRequest = new Request ( url , {
method : 'POST' ,
body : formBody ,
size : 1024
} ) ;
2020-03-13 08:06:25 -07:00
const bufferBody = Buffer . from ( bodyContent ) ;
2019-05-15 23:38:28 -07:00
const bufferRequest = new Request ( url , {
method : 'POST' ,
body : bufferBody ,
size : 1024
} ) ;
const stringRequest = new Request ( url , {
method : 'POST' ,
body : bodyContent ,
size : 1024
} ) ;
const nullRequest = new Request ( url , {
method : 'GET' ,
body : null ,
size : 1024
} ) ;
expect ( getTotalBytes ( streamRequest ) ) . to . be . null ;
expect ( getTotalBytes ( blobRequest ) ) . to . equal ( blobBody . size ) ;
expect ( getTotalBytes ( formRequest ) ) . to . not . be . null ;
expect ( getTotalBytes ( bufferRequest ) ) . to . equal ( bufferBody . length ) ;
expect ( getTotalBytes ( stringRequest ) ) . to . equal ( bodyContent . length ) ;
expect ( getTotalBytes ( nullRequest ) ) . to . equal ( 0 ) ;
expect ( extractContentType ( streamBody ) ) . to . be . null ;
expect ( extractContentType ( blobBody ) ) . to . equal ( 'text/plain' ) ;
expect ( extractContentType ( formBody ) ) . to . startWith ( 'multipart/form-data' ) ;
expect ( extractContentType ( bufferBody ) ) . to . be . null ;
expect ( extractContentType ( bodyContent ) ) . to . equal ( 'text/plain;charset=UTF-8' ) ;
expect ( extractContentType ( null ) ) . to . be . null ;
} ) ;
2016-03-19 03:06:33 -07:00
2020-06-13 02:34:59 -07:00
it ( 'should encode URLs as UTF-8' , async ( ) => {
2020-03-13 08:06:25 -07:00
const url = ` ${ base } möbius ` ;
2020-06-13 02:34:59 -07:00
const res = await fetch ( url ) ;
expect ( res . url ) . to . equal ( ` ${ base } m%C3%B6bius ` ) ;
2017-07-02 09:32:48 -07:00
} ) ;
} ) ;