test.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. // test tools
  2. var chai = require('chai');
  3. var cap = require('chai-as-promised');
  4. chai.use(cap);
  5. var expect = chai.expect;
  6. var bluebird = require('bluebird');
  7. var then = require('promise');
  8. var spawn = require('child_process').spawn;
  9. var stream = require('stream');
  10. var resumer = require('resumer');
  11. var FormData = require('form-data');
  12. var http = require('http');
  13. var fs = require('fs');
  14. var TestServer = require('./server');
  15. // test subjects
  16. var fetch = require('../index.js');
  17. var Headers = require('../lib/headers.js');
  18. var Response = require('../lib/response.js');
  19. var Request = require('../lib/request.js');
  20. var Body = require('../lib/body.js');
  21. var FetchError = require('../lib/fetch-error.js');
  22. // test with native promise on node 0.11, and bluebird for node 0.10
  23. fetch.Promise = fetch.Promise || bluebird;
  24. var url, opts, local, base;
  25. describe('node-fetch', function() {
  26. before(function(done) {
  27. local = new TestServer();
  28. base = 'http://' + local.hostname + ':' + local.port;
  29. local.start(done);
  30. });
  31. after(function(done) {
  32. local.stop(done);
  33. });
  34. it('should return a promise', function() {
  35. url = 'http://example.com/';
  36. var p = fetch(url);
  37. expect(p).to.be.an.instanceof(fetch.Promise);
  38. expect(p).to.have.property('then');
  39. });
  40. it('should allow custom promise', function() {
  41. url = 'http://example.com/';
  42. var old = fetch.Promise;
  43. fetch.Promise = then;
  44. expect(fetch(url)).to.be.an.instanceof(then);
  45. expect(fetch(url)).to.not.be.an.instanceof(bluebird);
  46. fetch.Promise = old;
  47. });
  48. it('should throw error when no promise implementation are found', function() {
  49. url = 'http://example.com/';
  50. var old = fetch.Promise;
  51. fetch.Promise = undefined;
  52. expect(function() {
  53. fetch(url)
  54. }).to.throw(Error);
  55. fetch.Promise = old;
  56. });
  57. it('should expose Headers, Response and Request constructors', function() {
  58. expect(fetch.Headers).to.equal(Headers);
  59. expect(fetch.Response).to.equal(Response);
  60. expect(fetch.Request).to.equal(Request);
  61. });
  62. it('should reject with error if url is protocol relative', function() {
  63. url = '//example.com/';
  64. return expect(fetch(url)).to.eventually.be.rejectedWith(Error);
  65. });
  66. it('should reject with error if url is relative path', function() {
  67. url = '/some/path';
  68. return expect(fetch(url)).to.eventually.be.rejectedWith(Error);
  69. });
  70. it('should reject with error if protocol is unsupported', function() {
  71. url = 'ftp://example.com/';
  72. return expect(fetch(url)).to.eventually.be.rejectedWith(Error);
  73. });
  74. it('should reject with error on network failure', function() {
  75. url = 'http://localhost:50000/';
  76. return expect(fetch(url)).to.eventually.be.rejected
  77. .and.be.an.instanceOf(FetchError)
  78. .and.include({ type: 'system', code: 'ECONNREFUSED', errno: 'ECONNREFUSED' });
  79. });
  80. it('should resolve into response', function() {
  81. url = base + '/hello';
  82. return fetch(url).then(function(res) {
  83. expect(res).to.be.an.instanceof(Response);
  84. expect(res.headers).to.be.an.instanceof(Headers);
  85. expect(res.body).to.be.an.instanceof(stream.Transform);
  86. expect(res.bodyUsed).to.be.false;
  87. expect(res.url).to.equal(url);
  88. expect(res.ok).to.be.true;
  89. expect(res.status).to.equal(200);
  90. expect(res.statusText).to.equal('OK');
  91. });
  92. });
  93. it('should accept plain text response', function() {
  94. url = base + '/plain';
  95. return fetch(url).then(function(res) {
  96. expect(res.headers.get('content-type')).to.equal('text/plain');
  97. return res.text().then(function(result) {
  98. expect(res.bodyUsed).to.be.true;
  99. expect(result).to.be.a('string');
  100. expect(result).to.equal('text');
  101. });
  102. });
  103. });
  104. it('should accept html response (like plain text)', function() {
  105. url = base + '/html';
  106. return fetch(url).then(function(res) {
  107. expect(res.headers.get('content-type')).to.equal('text/html');
  108. return res.text().then(function(result) {
  109. expect(res.bodyUsed).to.be.true;
  110. expect(result).to.be.a('string');
  111. expect(result).to.equal('<html></html>');
  112. });
  113. });
  114. });
  115. it('should accept json response', function() {
  116. url = base + '/json';
  117. return fetch(url).then(function(res) {
  118. expect(res.headers.get('content-type')).to.equal('application/json');
  119. return res.json().then(function(result) {
  120. expect(res.bodyUsed).to.be.true;
  121. expect(result).to.be.an('object');
  122. expect(result).to.deep.equal({ name: 'value' });
  123. });
  124. });
  125. });
  126. it('should send request with custom headers', function() {
  127. url = base + '/inspect';
  128. opts = {
  129. headers: { 'x-custom-header': 'abc' }
  130. };
  131. return fetch(url, opts).then(function(res) {
  132. return res.json();
  133. }).then(function(res) {
  134. expect(res.headers['x-custom-header']).to.equal('abc');
  135. });
  136. });
  137. it('should accept headers instance', function() {
  138. url = base + '/inspect';
  139. opts = {
  140. headers: new Headers({ 'x-custom-header': 'abc' })
  141. };
  142. return fetch(url, opts).then(function(res) {
  143. return res.json();
  144. }).then(function(res) {
  145. expect(res.headers['x-custom-header']).to.equal('abc');
  146. });
  147. });
  148. it('should accept custom host header', function() {
  149. url = base + '/inspect';
  150. opts = {
  151. headers: {
  152. host: 'example.com'
  153. }
  154. };
  155. return fetch(url, opts).then(function(res) {
  156. return res.json();
  157. }).then(function(res) {
  158. expect(res.headers['host']).to.equal('example.com');
  159. });
  160. });
  161. it('should follow redirect code 301', function() {
  162. url = base + '/redirect/301';
  163. return fetch(url).then(function(res) {
  164. expect(res.url).to.equal(base + '/inspect');
  165. expect(res.status).to.equal(200);
  166. expect(res.ok).to.be.true;
  167. });
  168. });
  169. it('should follow redirect code 302', function() {
  170. url = base + '/redirect/302';
  171. return fetch(url).then(function(res) {
  172. expect(res.url).to.equal(base + '/inspect');
  173. expect(res.status).to.equal(200);
  174. });
  175. });
  176. it('should follow redirect code 303', function() {
  177. url = base + '/redirect/303';
  178. return fetch(url).then(function(res) {
  179. expect(res.url).to.equal(base + '/inspect');
  180. expect(res.status).to.equal(200);
  181. });
  182. });
  183. it('should follow redirect code 307', function() {
  184. url = base + '/redirect/307';
  185. return fetch(url).then(function(res) {
  186. expect(res.url).to.equal(base + '/inspect');
  187. expect(res.status).to.equal(200);
  188. });
  189. });
  190. it('should follow redirect code 308', function() {
  191. url = base + '/redirect/308';
  192. return fetch(url).then(function(res) {
  193. expect(res.url).to.equal(base + '/inspect');
  194. expect(res.status).to.equal(200);
  195. });
  196. });
  197. it('should follow redirect chain', function() {
  198. url = base + '/redirect/chain';
  199. return fetch(url).then(function(res) {
  200. expect(res.url).to.equal(base + '/inspect');
  201. expect(res.status).to.equal(200);
  202. });
  203. });
  204. it('should follow POST request redirect code 301 with GET', function() {
  205. url = base + '/redirect/301';
  206. opts = {
  207. method: 'POST'
  208. , body: 'a=1'
  209. };
  210. return fetch(url, opts).then(function(res) {
  211. expect(res.url).to.equal(base + '/inspect');
  212. expect(res.status).to.equal(200);
  213. return res.json().then(function(result) {
  214. expect(result.method).to.equal('GET');
  215. expect(result.body).to.equal('');
  216. });
  217. });
  218. });
  219. it('should follow POST request redirect code 302 with GET', function() {
  220. url = base + '/redirect/302';
  221. opts = {
  222. method: 'POST'
  223. , body: 'a=1'
  224. };
  225. return fetch(url, opts).then(function(res) {
  226. expect(res.url).to.equal(base + '/inspect');
  227. expect(res.status).to.equal(200);
  228. return res.json().then(function(result) {
  229. expect(result.method).to.equal('GET');
  230. expect(result.body).to.equal('');
  231. });
  232. });
  233. });
  234. it('should follow redirect code 303 with GET', function() {
  235. url = base + '/redirect/303';
  236. opts = {
  237. method: 'PUT'
  238. , body: 'a=1'
  239. };
  240. return fetch(url, opts).then(function(res) {
  241. expect(res.url).to.equal(base + '/inspect');
  242. expect(res.status).to.equal(200);
  243. return res.json().then(function(result) {
  244. expect(result.method).to.equal('GET');
  245. expect(result.body).to.equal('');
  246. });
  247. });
  248. });
  249. it('should obey maximum redirect, reject case', function() {
  250. url = base + '/redirect/chain';
  251. opts = {
  252. follow: 1
  253. }
  254. return expect(fetch(url, opts)).to.eventually.be.rejected
  255. .and.be.an.instanceOf(FetchError)
  256. .and.have.property('type', 'max-redirect');
  257. });
  258. it('should obey redirect chain, resolve case', function() {
  259. url = base + '/redirect/chain';
  260. opts = {
  261. follow: 2
  262. }
  263. return fetch(url, opts).then(function(res) {
  264. expect(res.url).to.equal(base + '/inspect');
  265. expect(res.status).to.equal(200);
  266. });
  267. });
  268. it('should allow not following redirect', function() {
  269. url = base + '/redirect/301';
  270. opts = {
  271. follow: 0
  272. }
  273. return expect(fetch(url, opts)).to.eventually.be.rejected
  274. .and.be.an.instanceOf(FetchError)
  275. .and.have.property('type', 'max-redirect');
  276. });
  277. it('should support redirect mode, manual flag', function() {
  278. url = base + '/redirect/301';
  279. opts = {
  280. redirect: 'manual'
  281. };
  282. return fetch(url, opts).then(function(res) {
  283. expect(res.url).to.equal(url);
  284. expect(res.status).to.equal(301);
  285. expect(res.headers.get('location')).to.equal(base + '/inspect');
  286. });
  287. });
  288. it('should support redirect mode, error flag', function() {
  289. url = base + '/redirect/301';
  290. opts = {
  291. redirect: 'error'
  292. };
  293. return expect(fetch(url, opts)).to.eventually.be.rejected
  294. .and.be.an.instanceOf(FetchError)
  295. .and.have.property('type', 'no-redirect');
  296. });
  297. it('should support redirect mode, manual flag when there is no redirect', function() {
  298. url = base + '/hello';
  299. opts = {
  300. redirect: 'manual'
  301. };
  302. return fetch(url, opts).then(function(res) {
  303. expect(res.url).to.equal(url);
  304. expect(res.status).to.equal(200);
  305. expect(res.headers.get('location')).to.be.null;
  306. });
  307. });
  308. it('should follow redirect code 301 and keep existing headers', function() {
  309. url = base + '/redirect/301';
  310. opts = {
  311. headers: new Headers({ 'x-custom-header': 'abc' })
  312. };
  313. return fetch(url, opts).then(function(res) {
  314. expect(res.url).to.equal(base + '/inspect');
  315. return res.json();
  316. }).then(function(res) {
  317. expect(res.headers['x-custom-header']).to.equal('abc');
  318. });
  319. });
  320. it('should reject broken redirect', function() {
  321. url = base + '/error/redirect';
  322. return expect(fetch(url)).to.eventually.be.rejected
  323. .and.be.an.instanceOf(FetchError)
  324. .and.have.property('type', 'invalid-redirect');
  325. });
  326. it('should not reject broken redirect under manual redirect', function() {
  327. url = base + '/error/redirect';
  328. opts = {
  329. redirect: 'manual'
  330. };
  331. return fetch(url, opts).then(function(res) {
  332. expect(res.url).to.equal(url);
  333. expect(res.status).to.equal(301);
  334. expect(res.headers.get('location')).to.be.null;
  335. });
  336. });
  337. it('should handle client-error response', function() {
  338. url = base + '/error/400';
  339. return fetch(url).then(function(res) {
  340. expect(res.headers.get('content-type')).to.equal('text/plain');
  341. expect(res.status).to.equal(400);
  342. expect(res.statusText).to.equal('Bad Request');
  343. expect(res.ok).to.be.false;
  344. return res.text().then(function(result) {
  345. expect(res.bodyUsed).to.be.true;
  346. expect(result).to.be.a('string');
  347. expect(result).to.equal('client error');
  348. });
  349. });
  350. });
  351. it('should handle server-error response', function() {
  352. url = base + '/error/500';
  353. return fetch(url).then(function(res) {
  354. expect(res.headers.get('content-type')).to.equal('text/plain');
  355. expect(res.status).to.equal(500);
  356. expect(res.statusText).to.equal('Internal Server Error');
  357. expect(res.ok).to.be.false;
  358. return res.text().then(function(result) {
  359. expect(res.bodyUsed).to.be.true;
  360. expect(result).to.be.a('string');
  361. expect(result).to.equal('server error');
  362. });
  363. });
  364. });
  365. it('should handle network-error response', function() {
  366. url = base + '/error/reset';
  367. return expect(fetch(url)).to.eventually.be.rejected
  368. .and.be.an.instanceOf(FetchError)
  369. .and.have.property('code', 'ECONNRESET');
  370. });
  371. it('should handle DNS-error response', function() {
  372. url = 'http://domain.invalid';
  373. return expect(fetch(url)).to.eventually.be.rejected
  374. .and.be.an.instanceOf(FetchError)
  375. .and.have.property('code', 'ENOTFOUND');
  376. });
  377. it('should reject invalid json response', function() {
  378. url = base + '/error/json';
  379. return fetch(url).then(function(res) {
  380. expect(res.headers.get('content-type')).to.equal('application/json');
  381. return expect(res.json()).to.eventually.be.rejectedWith(Error);
  382. });
  383. });
  384. it('should handle no content response', function() {
  385. url = base + '/no-content';
  386. return fetch(url).then(function(res) {
  387. expect(res.status).to.equal(204);
  388. expect(res.statusText).to.equal('No Content');
  389. expect(res.ok).to.be.true;
  390. return res.text().then(function(result) {
  391. expect(result).to.be.a('string');
  392. expect(result).to.be.empty;
  393. });
  394. });
  395. });
  396. it('should throw on no-content json response', function() {
  397. url = base + '/no-content';
  398. return fetch(url).then(function(res) {
  399. return expect(res.json()).to.eventually.be.rejectedWith(FetchError);
  400. });
  401. });
  402. it('should handle no content response with gzip encoding', function() {
  403. url = base + '/no-content/gzip';
  404. return fetch(url).then(function(res) {
  405. expect(res.status).to.equal(204);
  406. expect(res.statusText).to.equal('No Content');
  407. expect(res.headers.get('content-encoding')).to.equal('gzip');
  408. expect(res.ok).to.be.true;
  409. return res.text().then(function(result) {
  410. expect(result).to.be.a('string');
  411. expect(result).to.be.empty;
  412. });
  413. });
  414. });
  415. it('should handle not modified response', function() {
  416. url = base + '/not-modified';
  417. return fetch(url).then(function(res) {
  418. expect(res.status).to.equal(304);
  419. expect(res.statusText).to.equal('Not Modified');
  420. expect(res.ok).to.be.false;
  421. return res.text().then(function(result) {
  422. expect(result).to.be.a('string');
  423. expect(result).to.be.empty;
  424. });
  425. });
  426. });
  427. it('should handle not modified response with gzip encoding', function() {
  428. url = base + '/not-modified/gzip';
  429. return fetch(url).then(function(res) {
  430. expect(res.status).to.equal(304);
  431. expect(res.statusText).to.equal('Not Modified');
  432. expect(res.headers.get('content-encoding')).to.equal('gzip');
  433. expect(res.ok).to.be.false;
  434. return res.text().then(function(result) {
  435. expect(result).to.be.a('string');
  436. expect(result).to.be.empty;
  437. });
  438. });
  439. });
  440. it('should decompress gzip response', function() {
  441. url = base + '/gzip';
  442. return fetch(url).then(function(res) {
  443. expect(res.headers.get('content-type')).to.equal('text/plain');
  444. return res.text().then(function(result) {
  445. expect(result).to.be.a('string');
  446. expect(result).to.equal('hello world');
  447. });
  448. });
  449. });
  450. it('should decompress deflate response', function() {
  451. url = base + '/deflate';
  452. return fetch(url).then(function(res) {
  453. expect(res.headers.get('content-type')).to.equal('text/plain');
  454. return res.text().then(function(result) {
  455. expect(result).to.be.a('string');
  456. expect(result).to.equal('hello world');
  457. });
  458. });
  459. });
  460. it('should decompress deflate raw response from old apache server', function() {
  461. url = base + '/deflate-raw';
  462. return fetch(url).then(function(res) {
  463. expect(res.headers.get('content-type')).to.equal('text/plain');
  464. return res.text().then(function(result) {
  465. expect(result).to.be.a('string');
  466. expect(result).to.equal('hello world');
  467. });
  468. });
  469. });
  470. it('should skip decompression if unsupported', function() {
  471. url = base + '/sdch';
  472. return fetch(url).then(function(res) {
  473. expect(res.headers.get('content-type')).to.equal('text/plain');
  474. return res.text().then(function(result) {
  475. expect(result).to.be.a('string');
  476. expect(result).to.equal('fake sdch string');
  477. });
  478. });
  479. });
  480. it('should reject if response compression is invalid', function() {
  481. url = base + '/invalid-content-encoding';
  482. return fetch(url).then(function(res) {
  483. expect(res.headers.get('content-type')).to.equal('text/plain');
  484. return expect(res.text()).to.eventually.be.rejected
  485. .and.be.an.instanceOf(FetchError)
  486. .and.have.property('code', 'Z_DATA_ERROR');
  487. });
  488. });
  489. it('should allow disabling auto decompression', function() {
  490. url = base + '/gzip';
  491. opts = {
  492. compress: false
  493. };
  494. return fetch(url, opts).then(function(res) {
  495. expect(res.headers.get('content-type')).to.equal('text/plain');
  496. return res.text().then(function(result) {
  497. expect(result).to.be.a('string');
  498. expect(result).to.not.equal('hello world');
  499. });
  500. });
  501. });
  502. it('should allow custom timeout', function() {
  503. this.timeout(500);
  504. url = base + '/timeout';
  505. opts = {
  506. timeout: 100
  507. };
  508. return expect(fetch(url, opts)).to.eventually.be.rejected
  509. .and.be.an.instanceOf(FetchError)
  510. .and.have.property('type', 'request-timeout');
  511. });
  512. it('should allow custom timeout on response body', function() {
  513. this.timeout(500);
  514. url = base + '/slow';
  515. opts = {
  516. timeout: 100
  517. };
  518. return fetch(url, opts).then(function(res) {
  519. expect(res.ok).to.be.true;
  520. return expect(res.text()).to.eventually.be.rejected
  521. .and.be.an.instanceOf(FetchError)
  522. .and.have.property('type', 'body-timeout');
  523. });
  524. });
  525. it('should clear internal timeout on fetch response', function (done) {
  526. this.timeout(1000);
  527. spawn('node', ['-e', 'require("./")("' + base + '/hello", { timeout: 5000 })'])
  528. .on('exit', function () {
  529. done();
  530. });
  531. });
  532. it('should clear internal timeout on fetch redirect', function (done) {
  533. this.timeout(1000);
  534. spawn('node', ['-e', 'require("./")("' + base + '/redirect/301", { timeout: 5000 })'])
  535. .on('exit', function () {
  536. done();
  537. });
  538. });
  539. it('should clear internal timeout on fetch error', function (done) {
  540. this.timeout(1000);
  541. spawn('node', ['-e', 'require("./")("' + base + '/error/reset", { timeout: 5000 })'])
  542. .on('exit', function () {
  543. done();
  544. });
  545. });
  546. it('should allow POST request', function() {
  547. url = base + '/inspect';
  548. opts = {
  549. method: 'POST'
  550. };
  551. return fetch(url, opts).then(function(res) {
  552. return res.json();
  553. }).then(function(res) {
  554. expect(res.method).to.equal('POST');
  555. expect(res.headers['transfer-encoding']).to.be.undefined;
  556. expect(res.headers['content-length']).to.equal('0');
  557. });
  558. });
  559. it('should allow POST request with string body', function() {
  560. url = base + '/inspect';
  561. opts = {
  562. method: 'POST'
  563. , body: 'a=1'
  564. };
  565. return fetch(url, opts).then(function(res) {
  566. return res.json();
  567. }).then(function(res) {
  568. expect(res.method).to.equal('POST');
  569. expect(res.body).to.equal('a=1');
  570. expect(res.headers['transfer-encoding']).to.be.undefined;
  571. expect(res.headers['content-length']).to.equal('3');
  572. });
  573. });
  574. it('should allow POST request with buffer body', function() {
  575. url = base + '/inspect';
  576. opts = {
  577. method: 'POST'
  578. , body: new Buffer('a=1', 'utf-8')
  579. };
  580. return fetch(url, opts).then(function(res) {
  581. return res.json();
  582. }).then(function(res) {
  583. expect(res.method).to.equal('POST');
  584. expect(res.body).to.equal('a=1');
  585. expect(res.headers['transfer-encoding']).to.equal('chunked');
  586. expect(res.headers['content-length']).to.be.undefined;
  587. });
  588. });
  589. it('should allow POST request with readable stream as body', function() {
  590. var body = resumer().queue('a=1').end();
  591. body = body.pipe(new stream.PassThrough());
  592. url = base + '/inspect';
  593. opts = {
  594. method: 'POST'
  595. , body: body
  596. };
  597. return fetch(url, opts).then(function(res) {
  598. return res.json();
  599. }).then(function(res) {
  600. expect(res.method).to.equal('POST');
  601. expect(res.body).to.equal('a=1');
  602. expect(res.headers['transfer-encoding']).to.equal('chunked');
  603. expect(res.headers['content-length']).to.be.undefined;
  604. });
  605. });
  606. it('should allow POST request with form-data as body', function() {
  607. var form = new FormData();
  608. form.append('a','1');
  609. url = base + '/multipart';
  610. opts = {
  611. method: 'POST'
  612. , body: form
  613. };
  614. return fetch(url, opts).then(function(res) {
  615. return res.json();
  616. }).then(function(res) {
  617. expect(res.method).to.equal('POST');
  618. expect(res.headers['content-type']).to.contain('multipart/form-data');
  619. expect(res.headers['content-length']).to.be.a('string');
  620. expect(res.body).to.equal('a=1');
  621. });
  622. });
  623. it('should allow POST request with form-data using stream as body', function() {
  624. var form = new FormData();
  625. form.append('my_field', fs.createReadStream('test/dummy.txt'));
  626. url = base + '/multipart';
  627. opts = {
  628. method: 'POST'
  629. , body: form
  630. };
  631. return fetch(url, opts).then(function(res) {
  632. return res.json();
  633. }).then(function(res) {
  634. expect(res.method).to.equal('POST');
  635. expect(res.headers['content-type']).to.contain('multipart/form-data');
  636. expect(res.headers['content-length']).to.be.undefined;
  637. expect(res.body).to.contain('my_field=');
  638. });
  639. });
  640. it('should allow POST request with form-data as body and custom headers', function() {
  641. var form = new FormData();
  642. form.append('a','1');
  643. var headers = form.getHeaders();
  644. headers['b'] = '2';
  645. url = base + '/multipart';
  646. opts = {
  647. method: 'POST'
  648. , body: form
  649. , headers: headers
  650. };
  651. return fetch(url, opts).then(function(res) {
  652. return res.json();
  653. }).then(function(res) {
  654. expect(res.method).to.equal('POST');
  655. expect(res.headers['content-type']).to.contain('multipart/form-data');
  656. expect(res.headers['content-length']).to.be.a('string');
  657. expect(res.headers.b).to.equal('2');
  658. expect(res.body).to.equal('a=1');
  659. });
  660. });
  661. it('should allow POST request with object body', function() {
  662. url = base + '/inspect';
  663. // note that fetch simply calls tostring on an object
  664. opts = {
  665. method: 'POST'
  666. , body: { a:1 }
  667. };
  668. return fetch(url, opts).then(function(res) {
  669. return res.json();
  670. }).then(function(res) {
  671. expect(res.method).to.equal('POST');
  672. expect(res.body).to.equal('[object Object]');
  673. });
  674. });
  675. it('should allow PUT request', function() {
  676. url = base + '/inspect';
  677. opts = {
  678. method: 'PUT'
  679. , body: 'a=1'
  680. };
  681. return fetch(url, opts).then(function(res) {
  682. return res.json();
  683. }).then(function(res) {
  684. expect(res.method).to.equal('PUT');
  685. expect(res.body).to.equal('a=1');
  686. });
  687. });
  688. it('should allow DELETE request', function() {
  689. url = base + '/inspect';
  690. opts = {
  691. method: 'DELETE'
  692. };
  693. return fetch(url, opts).then(function(res) {
  694. return res.json();
  695. }).then(function(res) {
  696. expect(res.method).to.equal('DELETE');
  697. });
  698. });
  699. it('should allow POST request with string body', function() {
  700. url = base + '/inspect';
  701. opts = {
  702. method: 'POST'
  703. , body: 'a=1'
  704. };
  705. return fetch(url, opts).then(function(res) {
  706. return res.json();
  707. }).then(function(res) {
  708. expect(res.method).to.equal('POST');
  709. expect(res.body).to.equal('a=1');
  710. expect(res.headers['transfer-encoding']).to.be.undefined;
  711. expect(res.headers['content-length']).to.equal('3');
  712. });
  713. });
  714. it('should allow DELETE request with string body', function() {
  715. url = base + '/inspect';
  716. opts = {
  717. method: 'DELETE'
  718. , body: 'a=1'
  719. };
  720. return fetch(url, opts).then(function(res) {
  721. return res.json();
  722. }).then(function(res) {
  723. expect(res.method).to.equal('DELETE');
  724. expect(res.body).to.equal('a=1');
  725. expect(res.headers['transfer-encoding']).to.be.undefined;
  726. expect(res.headers['content-length']).to.equal('3');
  727. });
  728. });
  729. it('should allow PATCH request', function() {
  730. url = base + '/inspect';
  731. opts = {
  732. method: 'PATCH'
  733. , body: 'a=1'
  734. };
  735. return fetch(url, opts).then(function(res) {
  736. return res.json();
  737. }).then(function(res) {
  738. expect(res.method).to.equal('PATCH');
  739. expect(res.body).to.equal('a=1');
  740. });
  741. });
  742. it('should allow HEAD request', function() {
  743. url = base + '/hello';
  744. opts = {
  745. method: 'HEAD'
  746. };
  747. return fetch(url, opts).then(function(res) {
  748. expect(res.status).to.equal(200);
  749. expect(res.statusText).to.equal('OK');
  750. expect(res.headers.get('content-type')).to.equal('text/plain');
  751. expect(res.body).to.be.an.instanceof(stream.Transform);
  752. return res.text();
  753. }).then(function(text) {
  754. expect(text).to.equal('');
  755. });
  756. });
  757. it('should allow HEAD request with content-encoding header', function() {
  758. url = base + '/error/404';
  759. opts = {
  760. method: 'HEAD'
  761. };
  762. return fetch(url, opts).then(function(res) {
  763. expect(res.status).to.equal(404);
  764. expect(res.headers.get('content-encoding')).to.equal('gzip');
  765. return res.text();
  766. }).then(function(text) {
  767. expect(text).to.equal('');
  768. });
  769. });
  770. it('should allow OPTIONS request', function() {
  771. url = base + '/options';
  772. opts = {
  773. method: 'OPTIONS'
  774. };
  775. return fetch(url, opts).then(function(res) {
  776. expect(res.status).to.equal(200);
  777. expect(res.statusText).to.equal('OK');
  778. expect(res.headers.get('allow')).to.equal('GET, HEAD, OPTIONS');
  779. expect(res.body).to.be.an.instanceof(stream.Transform);
  780. });
  781. });
  782. it('should reject decoding body twice', function() {
  783. url = base + '/plain';
  784. return fetch(url).then(function(res) {
  785. expect(res.headers.get('content-type')).to.equal('text/plain');
  786. return res.text().then(function(result) {
  787. expect(res.bodyUsed).to.be.true;
  788. return expect(res.text()).to.eventually.be.rejectedWith(Error);
  789. });
  790. });
  791. });
  792. it('should support maximum response size, multiple chunk', function() {
  793. url = base + '/size/chunk';
  794. opts = {
  795. size: 5
  796. };
  797. return fetch(url, opts).then(function(res) {
  798. expect(res.status).to.equal(200);
  799. expect(res.headers.get('content-type')).to.equal('text/plain');
  800. return expect(res.text()).to.eventually.be.rejected
  801. .and.be.an.instanceOf(FetchError)
  802. .and.have.property('type', 'max-size');
  803. });
  804. });
  805. it('should support maximum response size, single chunk', function() {
  806. url = base + '/size/long';
  807. opts = {
  808. size: 5
  809. };
  810. return fetch(url, opts).then(function(res) {
  811. expect(res.status).to.equal(200);
  812. expect(res.headers.get('content-type')).to.equal('text/plain');
  813. return expect(res.text()).to.eventually.be.rejected
  814. .and.be.an.instanceOf(FetchError)
  815. .and.have.property('type', 'max-size');
  816. });
  817. });
  818. it('should support encoding decode, xml dtd detect', function() {
  819. url = base + '/encoding/euc-jp';
  820. return fetch(url).then(function(res) {
  821. expect(res.status).to.equal(200);
  822. return res.text().then(function(result) {
  823. expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>日本語</title>');
  824. });
  825. });
  826. });
  827. it('should support encoding decode, content-type detect', function() {
  828. url = base + '/encoding/shift-jis';
  829. return fetch(url).then(function(res) {
  830. expect(res.status).to.equal(200);
  831. return res.text().then(function(result) {
  832. expect(result).to.equal('<div>日本語</div>');
  833. });
  834. });
  835. });
  836. it('should support encoding decode, html5 detect', function() {
  837. url = base + '/encoding/gbk';
  838. return fetch(url).then(function(res) {
  839. expect(res.status).to.equal(200);
  840. return res.text().then(function(result) {
  841. expect(result).to.equal('<meta charset="gbk"><div>中文</div>');
  842. });
  843. });
  844. });
  845. it('should support encoding decode, html4 detect', function() {
  846. url = base + '/encoding/gb2312';
  847. return fetch(url).then(function(res) {
  848. expect(res.status).to.equal(200);
  849. return res.text().then(function(result) {
  850. expect(result).to.equal('<meta http-equiv="Content-Type" content="text/html; charset=gb2312"><div>中文</div>');
  851. });
  852. });
  853. });
  854. it('should default to utf8 encoding', function() {
  855. url = base + '/encoding/utf8';
  856. return fetch(url).then(function(res) {
  857. expect(res.status).to.equal(200);
  858. expect(res.headers.get('content-type')).to.be.null;
  859. return res.text().then(function(result) {
  860. expect(result).to.equal('中文');
  861. });
  862. });
  863. });
  864. it('should support uncommon content-type order, charset in front', function() {
  865. url = base + '/encoding/order1';
  866. return fetch(url).then(function(res) {
  867. expect(res.status).to.equal(200);
  868. return res.text().then(function(result) {
  869. expect(result).to.equal('中文');
  870. });
  871. });
  872. });
  873. it('should support uncommon content-type order, end with qs', function() {
  874. url = base + '/encoding/order2';
  875. return fetch(url).then(function(res) {
  876. expect(res.status).to.equal(200);
  877. return res.text().then(function(result) {
  878. expect(result).to.equal('中文');
  879. });
  880. });
  881. });
  882. it('should support chunked encoding, html4 detect', function() {
  883. url = base + '/encoding/chunked';
  884. return fetch(url).then(function(res) {
  885. expect(res.status).to.equal(200);
  886. // because node v0.12 doesn't have str.repeat
  887. var padding = new Array(10 + 1).join('a');
  888. return res.text().then(function(result) {
  889. expect(result).to.equal(padding + '<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" /><div>日本語</div>');
  890. });
  891. });
  892. });
  893. it('should only do encoding detection up to 1024 bytes', function() {
  894. url = base + '/encoding/invalid';
  895. return fetch(url).then(function(res) {
  896. expect(res.status).to.equal(200);
  897. // because node v0.12 doesn't have str.repeat
  898. var padding = new Array(1200 + 1).join('a');
  899. return res.text().then(function(result) {
  900. expect(result).to.not.equal(padding + '中文');
  901. });
  902. });
  903. });
  904. it('should allow piping response body as stream', function(done) {
  905. url = base + '/hello';
  906. fetch(url).then(function(res) {
  907. expect(res.body).to.be.an.instanceof(stream.Transform);
  908. res.body.on('data', function(chunk) {
  909. if (chunk === null) {
  910. return;
  911. }
  912. expect(chunk.toString()).to.equal('world');
  913. });
  914. res.body.on('end', function() {
  915. done();
  916. });
  917. });
  918. });
  919. it('should allow cloning a response, and use both as stream', function(done) {
  920. url = base + '/hello';
  921. return fetch(url).then(function(res) {
  922. var counter = 0;
  923. var r1 = res.clone();
  924. expect(res.body).to.be.an.instanceof(stream.Transform);
  925. expect(r1.body).to.be.an.instanceof(stream.Transform);
  926. res.body.on('data', function(chunk) {
  927. if (chunk === null) {
  928. return;
  929. }
  930. expect(chunk.toString()).to.equal('world');
  931. });
  932. res.body.on('end', function() {
  933. counter++;
  934. if (counter == 2) {
  935. done();
  936. }
  937. });
  938. r1.body.on('data', function(chunk) {
  939. if (chunk === null) {
  940. return;
  941. }
  942. expect(chunk.toString()).to.equal('world');
  943. });
  944. r1.body.on('end', function() {
  945. counter++;
  946. if (counter == 2) {
  947. done();
  948. }
  949. });
  950. });
  951. });
  952. it('should allow cloning a json response and log it as text response', function() {
  953. url = base + '/json';
  954. return fetch(url).then(function(res) {
  955. var r1 = res.clone();
  956. return fetch.Promise.all([res.json(), r1.text()]).then(function(results) {
  957. expect(results[0]).to.deep.equal({name: 'value'});
  958. expect(results[1]).to.equal('{"name":"value"}');
  959. });
  960. });
  961. });
  962. it('should allow cloning a json response, and then log it as text response', function() {
  963. url = base + '/json';
  964. return fetch(url).then(function(res) {
  965. var r1 = res.clone();
  966. return res.json().then(function(result) {
  967. expect(result).to.deep.equal({name: 'value'});
  968. return r1.text().then(function(result) {
  969. expect(result).to.equal('{"name":"value"}');
  970. });
  971. });
  972. });
  973. });
  974. it('should allow cloning a json response, first log as text response, then return json object', function() {
  975. url = base + '/json';
  976. return fetch(url).then(function(res) {
  977. var r1 = res.clone();
  978. return r1.text().then(function(result) {
  979. expect(result).to.equal('{"name":"value"}');
  980. return res.json().then(function(result) {
  981. expect(result).to.deep.equal({name: 'value'});
  982. });
  983. });
  984. });
  985. });
  986. it('should not allow cloning a response after its been used', function() {
  987. url = base + '/hello';
  988. return fetch(url).then(function(res) {
  989. return res.text().then(function(result) {
  990. expect(function() {
  991. var r1 = res.clone();
  992. }).to.throw(Error);
  993. });
  994. })
  995. });
  996. it('should allow get all responses of a header', function() {
  997. url = base + '/cookie';
  998. return fetch(url).then(function(res) {
  999. expect(res.headers.get('set-cookie')).to.equal('a=1');
  1000. expect(res.headers.get('Set-Cookie')).to.equal('a=1');
  1001. expect(res.headers.getAll('set-cookie')).to.deep.equal(['a=1', 'b=1']);
  1002. expect(res.headers.getAll('Set-Cookie')).to.deep.equal(['a=1', 'b=1']);
  1003. });
  1004. });
  1005. it('should allow iterating through all headers', function() {
  1006. var headers = new Headers({
  1007. a: 1
  1008. , b: [2, 3]
  1009. , c: [4]
  1010. });
  1011. expect(headers).to.have.property('forEach');
  1012. var result = [];
  1013. headers.forEach(function(val, key) {
  1014. result.push([key, val]);
  1015. });
  1016. expected = [
  1017. ["a", "1"]
  1018. , ["b", "2"]
  1019. , ["b", "3"]
  1020. , ["c", "4"]
  1021. ];
  1022. expect(result).to.deep.equal(expected);
  1023. });
  1024. it('should allow deleting header', function() {
  1025. url = base + '/cookie';
  1026. return fetch(url).then(function(res) {
  1027. res.headers.delete('set-cookie');
  1028. expect(res.headers.get('set-cookie')).to.be.null;
  1029. expect(res.headers.getAll('set-cookie')).to.be.empty;
  1030. });
  1031. });
  1032. it('should send request with connection keep-alive if agent is provided', function() {
  1033. url = base + '/inspect';
  1034. opts = {
  1035. agent: new http.Agent({
  1036. keepAlive: true
  1037. })
  1038. };
  1039. return fetch(url, opts).then(function(res) {
  1040. return res.json();
  1041. }).then(function(res) {
  1042. expect(res.headers['connection']).to.equal('keep-alive');
  1043. });
  1044. });
  1045. it('should ignore unsupported attributes while reading headers', function() {
  1046. var FakeHeader = function() {};
  1047. // prototypes are ignored
  1048. FakeHeader.prototype.z = 'fake';
  1049. var res = new FakeHeader;
  1050. // valid
  1051. res.a = 'string';
  1052. res.b = ['1','2'];
  1053. res.c = '';
  1054. res.d = [];
  1055. // common mistakes, normalized
  1056. res.e = 1;
  1057. res.f = [1, 2];
  1058. // invalid, ignored
  1059. res.g = { a:1 };
  1060. res.h = undefined;
  1061. res.i = null;
  1062. res.j = NaN;
  1063. res.k = true;
  1064. res.l = false;
  1065. res.m = new Buffer('test');
  1066. var h1 = new Headers(res);
  1067. expect(h1._headers['a']).to.include('string');
  1068. expect(h1._headers['b']).to.include('1');
  1069. expect(h1._headers['b']).to.include('2');
  1070. expect(h1._headers['c']).to.include('');
  1071. expect(h1._headers['d']).to.be.undefined;
  1072. expect(h1._headers['e']).to.include('1');
  1073. expect(h1._headers['f']).to.include('1');
  1074. expect(h1._headers['f']).to.include('2');
  1075. expect(h1._headers['g']).to.be.undefined;
  1076. expect(h1._headers['h']).to.be.undefined;
  1077. expect(h1._headers['i']).to.be.undefined;
  1078. expect(h1._headers['j']).to.be.undefined;
  1079. expect(h1._headers['k']).to.be.undefined;
  1080. expect(h1._headers['l']).to.be.undefined;
  1081. expect(h1._headers['m']).to.be.undefined;
  1082. expect(h1._headers['z']).to.be.undefined;
  1083. });
  1084. it('should wrap headers', function() {
  1085. var h1 = new Headers({
  1086. a: '1'
  1087. });
  1088. var h2 = new Headers(h1);
  1089. h2.set('b', '1');
  1090. var h3 = new Headers(h2);
  1091. h3.append('a', '2');
  1092. expect(h1._headers['a']).to.include('1');
  1093. expect(h1._headers['a']).to.not.include('2');
  1094. expect(h2._headers['a']).to.include('1');
  1095. expect(h2._headers['a']).to.not.include('2');
  1096. expect(h2._headers['b']).to.include('1');
  1097. expect(h3._headers['a']).to.include('1');
  1098. expect(h3._headers['a']).to.include('2');
  1099. expect(h3._headers['b']).to.include('1');
  1100. });
  1101. it('should support fetch with Request instance', function() {
  1102. url = base + '/hello';
  1103. var req = new Request(url);
  1104. return fetch(req).then(function(res) {
  1105. expect(res.url).to.equal(url);
  1106. expect(res.ok).to.be.true;
  1107. expect(res.status).to.equal(200);
  1108. });
  1109. });
  1110. it('should support wrapping Request instance', function() {
  1111. url = base + '/hello';
  1112. var form = new FormData();
  1113. form.append('a', '1');
  1114. var r1 = new Request(url, {
  1115. method: 'POST'
  1116. , follow: 1
  1117. , body: form
  1118. });
  1119. var r2 = new Request(r1, {
  1120. follow: 2
  1121. });
  1122. expect(r2.url).to.equal(url);
  1123. expect(r2.method).to.equal('POST');
  1124. // note that we didn't clone the body
  1125. expect(r2.body).to.equal(form);
  1126. expect(r1.follow).to.equal(1);
  1127. expect(r2.follow).to.equal(2);
  1128. expect(r1.counter).to.equal(0);
  1129. expect(r2.counter).to.equal(0);
  1130. });
  1131. it('should support overwrite Request instance', function() {
  1132. url = base + '/inspect';
  1133. var req = new Request(url, {
  1134. method: 'POST'
  1135. , headers: {
  1136. a: '1'
  1137. }
  1138. });
  1139. return fetch(req, {
  1140. method: 'GET'
  1141. , headers: {
  1142. a: '2'
  1143. }
  1144. }).then(function(res) {
  1145. return res.json();
  1146. }).then(function(body) {
  1147. expect(body.method).to.equal('GET');
  1148. expect(body.headers.a).to.equal('2');
  1149. });
  1150. });
  1151. it('should support empty options in Response constructor', function() {
  1152. var body = resumer().queue('a=1').end();
  1153. body = body.pipe(new stream.PassThrough());
  1154. var res = new Response(body);
  1155. return res.text().then(function(result) {
  1156. expect(result).to.equal('a=1');
  1157. });
  1158. });
  1159. it('should support parsing headers in Response constructor', function() {
  1160. var res = new Response(null, {
  1161. headers: {
  1162. a: '1'
  1163. }
  1164. });
  1165. expect(res.headers.get('a')).to.equal('1');
  1166. });
  1167. it('should support text() method in Response constructor', function() {
  1168. var res = new Response('a=1');
  1169. return res.text().then(function(result) {
  1170. expect(result).to.equal('a=1');
  1171. });
  1172. });
  1173. it('should support json() method in Response constructor', function() {
  1174. var res = new Response('{"a":1}');
  1175. return res.json().then(function(result) {
  1176. expect(result.a).to.equal(1);
  1177. });
  1178. });
  1179. it('should support buffer() method in Response constructor', function() {
  1180. var res = new Response('a=1');
  1181. return res.buffer().then(function(result) {
  1182. expect(result.toString()).to.equal('a=1');
  1183. });
  1184. });
  1185. it('should support clone() method in Response constructor', function() {
  1186. var body = resumer().queue('a=1').end();
  1187. body = body.pipe(new stream.PassThrough());
  1188. var res = new Response(body, {
  1189. headers: {
  1190. a: '1'
  1191. }
  1192. , url: base
  1193. , status: 346
  1194. , statusText: 'production'
  1195. });
  1196. var cl = res.clone();
  1197. expect(cl.headers.get('a')).to.equal('1');
  1198. expect(cl.url).to.equal(base);
  1199. expect(cl.status).to.equal(346);
  1200. expect(cl.statusText).to.equal('production');
  1201. expect(cl.ok).to.be.false;
  1202. // clone body shouldn't be the same body
  1203. expect(cl.body).to.not.equal(body);
  1204. return cl.text().then(function(result) {
  1205. expect(result).to.equal('a=1');
  1206. });
  1207. });
  1208. it('should support stream as body in Response constructor', function() {
  1209. var body = resumer().queue('a=1').end();
  1210. body = body.pipe(new stream.PassThrough());
  1211. var res = new Response(body);
  1212. return res.text().then(function(result) {
  1213. expect(result).to.equal('a=1');
  1214. });
  1215. });
  1216. it('should support string as body in Response constructor', function() {
  1217. var res = new Response('a=1');
  1218. return res.text().then(function(result) {
  1219. expect(result).to.equal('a=1');
  1220. });
  1221. });
  1222. it('should support buffer as body in Response constructor', function() {
  1223. var res = new Response(new Buffer('a=1'));
  1224. return res.text().then(function(result) {
  1225. expect(result).to.equal('a=1');
  1226. });
  1227. });
  1228. it('should default to 200 as status code', function() {
  1229. var res = new Response(null);
  1230. expect(res.status).to.equal(200);
  1231. });
  1232. it('should support parsing headers in Request constructor', function() {
  1233. url = base;
  1234. var req = new Request(url, {
  1235. headers: {
  1236. a: '1'
  1237. }
  1238. });
  1239. expect(req.url).to.equal(url);
  1240. expect(req.headers.get('a')).to.equal('1');
  1241. });
  1242. it('should support text() method in Request constructor', function() {
  1243. url = base;
  1244. var req = new Request(url, {
  1245. body: 'a=1'
  1246. });
  1247. expect(req.url).to.equal(url);
  1248. return req.text().then(function(result) {
  1249. expect(result).to.equal('a=1');
  1250. });
  1251. });
  1252. it('should support json() method in Request constructor', function() {
  1253. url = base;
  1254. var req = new Request(url, {
  1255. body: '{"a":1}'
  1256. });
  1257. expect(req.url).to.equal(url);
  1258. return req.json().then(function(result) {
  1259. expect(result.a).to.equal(1);
  1260. });
  1261. });
  1262. it('should support buffer() method in Request constructor', function() {
  1263. url = base;
  1264. var req = new Request(url, {
  1265. body: 'a=1'
  1266. });
  1267. expect(req.url).to.equal(url);
  1268. return req.buffer().then(function(result) {
  1269. expect(result.toString()).to.equal('a=1');
  1270. });
  1271. });
  1272. it('should support arbitrary url in Request constructor', function() {
  1273. url = 'anything';
  1274. var req = new Request(url);
  1275. expect(req.url).to.equal('anything');
  1276. });
  1277. it('should support clone() method in Request constructor', function() {
  1278. url = base;
  1279. var body = resumer().queue('a=1').end();
  1280. body = body.pipe(new stream.PassThrough());
  1281. var agent = new http.Agent();
  1282. var req = new Request(url, {
  1283. body: body
  1284. , method: 'POST'
  1285. , redirect: 'manual'
  1286. , headers: {
  1287. b: '2'
  1288. }
  1289. , follow: 3
  1290. , compress: false
  1291. , agent: agent
  1292. });
  1293. var cl = req.clone();
  1294. expect(cl.url).to.equal(url);
  1295. expect(cl.method).to.equal('POST');
  1296. expect(cl.redirect).to.equal('manual');
  1297. expect(cl.headers.get('b')).to.equal('2');
  1298. expect(cl.follow).to.equal(3);
  1299. expect(cl.compress).to.equal(false);
  1300. expect(cl.method).to.equal('POST');
  1301. expect(cl.counter).to.equal(0);
  1302. expect(cl.agent).to.equal(agent);
  1303. // clone body shouldn't be the same body
  1304. expect(cl.body).to.not.equal(body);
  1305. return fetch.Promise.all([cl.text(), req.text()]).then(function(results) {
  1306. expect(results[0]).to.equal('a=1');
  1307. expect(results[1]).to.equal('a=1');
  1308. });
  1309. });
  1310. it('should support text(), json() and buffer() method in Body constructor', function() {
  1311. var body = new Body('a=1');
  1312. expect(body).to.have.property('text');
  1313. expect(body).to.have.property('json');
  1314. expect(body).to.have.property('buffer');
  1315. });
  1316. it('should create custom FetchError', function funcName() {
  1317. var systemError = new Error('system');
  1318. systemError.code = 'ESOMEERROR';
  1319. var err = new FetchError('test message', 'test-error', systemError);
  1320. expect(err).to.be.an.instanceof(Error);
  1321. expect(err).to.be.an.instanceof(FetchError);
  1322. expect(err.name).to.equal('FetchError');
  1323. expect(err.message).to.equal('test message');
  1324. expect(err.type).to.equal('test-error');
  1325. expect(err.code).to.equal('ESOMEERROR');
  1326. expect(err.errno).to.equal('ESOMEERROR');
  1327. expect(err.stack).to.include('funcName');
  1328. expect(err.stack.split('\n')[0]).to.equal(err.name + ': ' + err.message);
  1329. });
  1330. it('should support https request', function() {
  1331. this.timeout(5000);
  1332. url = 'https://github.com/';
  1333. opts = {
  1334. method: 'HEAD'
  1335. };
  1336. return fetch(url, opts).then(function(res) {
  1337. expect(res.status).to.equal(200);
  1338. expect(res.ok).to.be.true;
  1339. });
  1340. });
  1341. });