core: Don't use global buffer (#1422)
* remove unused file * two test is coveraged by the Uint8Array test * use arrayBuffer to test base64 instead * avoid testing buffer * avoid using Buffer * import buffer module * use one same textEncoder * import stream consumer that can test iterable objects * fix a test * fix test where type should be empty
This commit is contained in:
parent
eb33090b81
commit
1493d046bc
|
@ -58,13 +58,14 @@
|
||||||
"formdata-node": "^4.2.4",
|
"formdata-node": "^4.2.4",
|
||||||
"mocha": "^9.1.3",
|
"mocha": "^9.1.3",
|
||||||
"p-timeout": "^5.0.0",
|
"p-timeout": "^5.0.0",
|
||||||
|
"stream-consumers": "^1.0.1",
|
||||||
"tsd": "^0.14.0",
|
"tsd": "^0.14.0",
|
||||||
"xo": "^0.39.1"
|
"xo": "^0.39.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"data-uri-to-buffer": "^4.0.0",
|
"data-uri-to-buffer": "^4.0.0",
|
||||||
"formdata-polyfill": "^4.0.10",
|
"fetch-blob": "^3.1.3",
|
||||||
"fetch-blob": "^3.1.3"
|
"formdata-polyfill": "^4.0.10"
|
||||||
},
|
},
|
||||||
"tsd": {
|
"tsd": {
|
||||||
"cwd": "@types",
|
"cwd": "@types",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import Stream, {PassThrough} from 'node:stream';
|
import Stream, {PassThrough} from 'node:stream';
|
||||||
import {types, deprecate, promisify} from 'node:util';
|
import {types, deprecate, promisify} from 'node:util';
|
||||||
|
import {Buffer} from 'node:buffer';
|
||||||
|
|
||||||
import Blob from 'fetch-blob';
|
import Blob from 'fetch-blob';
|
||||||
import {FormData, formDataToBlob} from 'formdata-polyfill/esm.min.js';
|
import {FormData, formDataToBlob} from 'formdata-polyfill/esm.min.js';
|
||||||
|
|
|
@ -10,6 +10,8 @@ import http from 'node:http';
|
||||||
import https from 'node:https';
|
import https from 'node:https';
|
||||||
import zlib from 'node:zlib';
|
import zlib from 'node:zlib';
|
||||||
import Stream, {PassThrough, pipeline as pump} from 'node:stream';
|
import Stream, {PassThrough, pipeline as pump} from 'node:stream';
|
||||||
|
import {Buffer} from 'node:buffer';
|
||||||
|
|
||||||
import dataUriToBuffer from 'data-uri-to-buffer';
|
import dataUriToBuffer from 'data-uri-to-buffer';
|
||||||
|
|
||||||
import {writeToStream, clone} from './body.js';
|
import {writeToStream, clone} from './body.js';
|
||||||
|
|
|
@ -5,15 +5,14 @@ const {expect} = chai;
|
||||||
|
|
||||||
describe('external encoding', () => {
|
describe('external encoding', () => {
|
||||||
describe('data uri', () => {
|
describe('data uri', () => {
|
||||||
it('should accept base64-encoded gif data uri', () => {
|
it('should accept base64-encoded gif data uri', async () => {
|
||||||
return fetch('data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=').then(r => {
|
const b64 = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
|
||||||
expect(r.status).to.equal(200);
|
const res = await fetch(b64);
|
||||||
expect(r.headers.get('Content-Type')).to.equal('image/gif');
|
expect(res.status).to.equal(200);
|
||||||
|
expect(res.headers.get('Content-Type')).to.equal('image/gif');
|
||||||
return r.buffer().then(b => {
|
const buf = await res.arrayBuffer();
|
||||||
expect(b).to.be.an.instanceOf(Buffer);
|
expect(buf.byteLength).to.equal(35);
|
||||||
});
|
expect(buf).to.be.an.instanceOf(ArrayBuffer);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should accept data uri with specified charset', async () => {
|
it('should accept data uri with specified charset', async () => {
|
||||||
|
|
|
@ -178,7 +178,6 @@ describe('Headers', () => {
|
||||||
res.j = Number.NaN;
|
res.j = Number.NaN;
|
||||||
res.k = true;
|
res.k = true;
|
||||||
res.l = false;
|
res.l = false;
|
||||||
res.m = Buffer.from('test');
|
|
||||||
|
|
||||||
const h1 = new Headers(res);
|
const h1 = new Headers(res);
|
||||||
h1.set('n', [1, 2]);
|
h1.set('n', [1, 2]);
|
||||||
|
@ -198,7 +197,6 @@ describe('Headers', () => {
|
||||||
expect(h1Raw.j).to.include('NaN');
|
expect(h1Raw.j).to.include('NaN');
|
||||||
expect(h1Raw.k).to.include('true');
|
expect(h1Raw.k).to.include('true');
|
||||||
expect(h1Raw.l).to.include('false');
|
expect(h1Raw.l).to.include('false');
|
||||||
expect(h1Raw.m).to.include('test');
|
|
||||||
expect(h1Raw.n).to.include('1,2');
|
expect(h1Raw.n).to.include('1,2');
|
||||||
expect(h1Raw.n).to.include('3,4');
|
expect(h1Raw.n).to.include('3,4');
|
||||||
|
|
||||||
|
|
89
test/main.js
89
test/main.js
|
@ -16,6 +16,7 @@ import {FormData as FormDataNode} from 'formdata-polyfill/esm.min.js';
|
||||||
import delay from 'delay';
|
import delay from 'delay';
|
||||||
import AbortControllerMysticatea from 'abort-controller';
|
import AbortControllerMysticatea from 'abort-controller';
|
||||||
import abortControllerPolyfill from 'abortcontroller-polyfill/dist/abortcontroller.js';
|
import abortControllerPolyfill from 'abortcontroller-polyfill/dist/abortcontroller.js';
|
||||||
|
import {text} from 'stream-consumers';
|
||||||
|
|
||||||
// Test subjects
|
// Test subjects
|
||||||
import Blob from 'fetch-blob';
|
import Blob from 'fetch-blob';
|
||||||
|
@ -36,6 +37,7 @@ import TestServer from './utils/server.js';
|
||||||
import chaiTimeout from './utils/chai-timeout.js';
|
import chaiTimeout from './utils/chai-timeout.js';
|
||||||
|
|
||||||
const AbortControllerPolyfill = abortControllerPolyfill.AbortController;
|
const AbortControllerPolyfill = abortControllerPolyfill.AbortController;
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
function isNodeLowerThan(version) {
|
function isNodeLowerThan(version) {
|
||||||
return !~process.version.localeCompare(version, undefined, {numeric: true});
|
return !~process.version.localeCompare(version, undefined, {numeric: true});
|
||||||
|
@ -51,18 +53,6 @@ chai.use(chaiString);
|
||||||
chai.use(chaiTimeout);
|
chai.use(chaiTimeout);
|
||||||
const {expect} = chai;
|
const {expect} = chai;
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('node-fetch', () => {
|
describe('node-fetch', () => {
|
||||||
const local = new TestServer();
|
const local = new TestServer();
|
||||||
let base;
|
let base;
|
||||||
|
@ -1314,25 +1304,7 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow POST request with buffer body', () => {
|
|
||||||
const url = `${base}inspect`;
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
body: Buffer.from('a=1', 'utf-8')
|
|
||||||
};
|
|
||||||
return fetch(url, options).then(res => {
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow POST request with ArrayBuffer body', () => {
|
it('should allow POST request with ArrayBuffer body', () => {
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -1351,7 +1323,7 @@ describe('node-fetch', () => {
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: new VMUint8Array(Buffer.from('Hello, world!\n')).buffer
|
body: new VMUint8Array(encoder.encode('Hello, world!\n')).buffer
|
||||||
};
|
};
|
||||||
return fetch(url, options).then(res => res.json()).then(res => {
|
return fetch(url, options).then(res => res.json()).then(res => {
|
||||||
expect(res.method).to.equal('POST');
|
expect(res.method).to.equal('POST');
|
||||||
|
@ -1363,7 +1335,6 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow POST request with ArrayBufferView (Uint8Array) body', () => {
|
it('should allow POST request with ArrayBufferView (Uint8Array) body', () => {
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -1379,7 +1350,6 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow POST request with ArrayBufferView (DataView) body', () => {
|
it('should allow POST request with ArrayBufferView (DataView) body', () => {
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -1398,7 +1368,7 @@ describe('node-fetch', () => {
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: new VMUint8Array(Buffer.from('Hello, world!\n'))
|
body: new VMUint8Array(encoder.encode('Hello, world!\n'))
|
||||||
};
|
};
|
||||||
return fetch(url, options).then(res => res.json()).then(res => {
|
return fetch(url, options).then(res => res.json()).then(res => {
|
||||||
expect(res.method).to.equal('POST');
|
expect(res.method).to.equal('POST');
|
||||||
|
@ -1410,7 +1380,6 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow POST request with ArrayBufferView (Uint8Array, offset, length) body', () => {
|
it('should allow POST request with ArrayBufferView (Uint8Array, offset, length) body', () => {
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const url = `${base}inspect`;
|
const url = `${base}inspect`;
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -1846,39 +1815,28 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow piping response body as stream', () => {
|
it('should allow piping response body as stream', async () => {
|
||||||
const url = `${base}hello`;
|
const url = `${base}hello`;
|
||||||
return fetch(url).then(res => {
|
const res = await fetch(url);
|
||||||
expect(res.body).to.be.an.instanceof(stream.Transform);
|
expect(res.body).to.be.an.instanceof(stream.Transform);
|
||||||
return streamToPromise(res.body, chunk => {
|
const body = await text(res.body);
|
||||||
if (chunk === null) {
|
expect(body).to.equal('world');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(chunk.toString()).to.equal('world');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow cloning a response, and use both as stream', () => {
|
it('should allow cloning a response, and use both as stream', async () => {
|
||||||
const url = `${base}hello`;
|
const url = `${base}hello`;
|
||||||
return fetch(url).then(res => {
|
const res = await fetch(url);
|
||||||
const r1 = res.clone();
|
const r1 = res.clone();
|
||||||
expect(res.body).to.be.an.instanceof(stream.Transform);
|
expect(res.body).to.be.an.instanceof(stream.Transform);
|
||||||
expect(r1.body).to.be.an.instanceof(stream.Transform);
|
expect(r1.body).to.be.an.instanceof(stream.Transform);
|
||||||
const dataHandler = chunk => {
|
|
||||||
if (chunk === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(chunk.toString()).to.equal('world');
|
const [t1, t2] = await Promise.all([
|
||||||
};
|
text(res.body),
|
||||||
|
text(r1.body)
|
||||||
return Promise.all([
|
|
||||||
streamToPromise(res.body, dataHandler),
|
|
||||||
streamToPromise(r1.body, dataHandler)
|
|
||||||
]);
|
]);
|
||||||
});
|
|
||||||
|
expect(t1).to.equal('world');
|
||||||
|
expect(t2).to.equal('world');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow cloning a json response and log it as text response', () => {
|
it('should allow cloning a json response and log it as text response', () => {
|
||||||
|
@ -2141,13 +2099,10 @@ describe('node-fetch', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support reading blob as stream', () => {
|
it('should support reading blob as stream', async () => {
|
||||||
return new Response('hello')
|
const blob = await new Response('hello').blob();
|
||||||
.blob()
|
const str = await text(blob.stream());
|
||||||
.then(blob => streamToPromise(stream.Readable.from(blob.stream()), data => {
|
expect(str).to.equal('hello');
|
||||||
const string = Buffer.from(data).toString();
|
|
||||||
expect(string).to.equal('hello');
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support blob round-trip', () => {
|
it('should support blob round-trip', () => {
|
||||||
|
@ -2233,7 +2188,7 @@ describe('node-fetch', () => {
|
||||||
// Issue #414
|
// Issue #414
|
||||||
it('should reject if attempt to accumulate body stream throws', () => {
|
it('should reject if attempt to accumulate body stream throws', () => {
|
||||||
const res = new Response(stream.Readable.from((async function * () {
|
const res = new Response(stream.Readable.from((async function * () {
|
||||||
yield Buffer.from('tada');
|
yield encoder.encode('tada');
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
setTimeout(resolve, 200);
|
setTimeout(resolve, 200);
|
||||||
});
|
});
|
||||||
|
@ -2329,7 +2284,7 @@ describe('node-fetch', () => {
|
||||||
size: 1024
|
size: 1024
|
||||||
});
|
});
|
||||||
|
|
||||||
const bufferBody = Buffer.from(bodyContent);
|
const bufferBody = encoder.encode(bodyContent);
|
||||||
const bufferRequest = new Request(url, {
|
const bufferRequest = new Request(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: bufferBody,
|
body: bufferBody,
|
||||||
|
|
|
@ -127,7 +127,7 @@ describe('Request constructor', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
const req = new Request('http://example.com', {referrer: 'foobar'});
|
const req = new Request('http://example.com', {referrer: 'foobar'});
|
||||||
expect.fail(req);
|
expect.fail(req);
|
||||||
}).to.throw(TypeError, 'Invalid URL: foobar');
|
}).to.throw(TypeError, /Invalid URL/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -201,18 +201,17 @@ describe('Request', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support blob() method', () => {
|
it('should support blob() method', async () => {
|
||||||
const url = base;
|
const url = base;
|
||||||
const request = new Request(url, {
|
const request = new Request(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: Buffer.from('a=1')
|
body: new TextEncoder().encode('a=1')
|
||||||
});
|
});
|
||||||
expect(request.url).to.equal(url);
|
expect(request.url).to.equal(url);
|
||||||
return request.blob().then(result => {
|
const blob = await request.blob();
|
||||||
expect(result).to.be.an.instanceOf(Blob);
|
expect(blob).to.be.an.instanceOf(Blob);
|
||||||
expect(result.size).to.equal(3);
|
expect(blob.size).to.equal(3);
|
||||||
expect(result.type).to.equal('');
|
expect(blob.type).to.equal('');
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support clone() method', () => {
|
it('should support clone() method', () => {
|
||||||
|
|
|
@ -154,13 +154,6 @@ describe('Response', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support buffer as body', () => {
|
|
||||||
const res = new Response(Buffer.from('a=1'));
|
|
||||||
return res.text().then(result => {
|
|
||||||
expect(result).to.equal('a=1');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support ArrayBuffer as body', () => {
|
it('should support ArrayBuffer as body', () => {
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
const res = new Response(encoder.encode('a=1'));
|
const res = new Response(encoder.encode('a=1'));
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
export default async function readStream(stream) {
|
|
||||||
const chunks = [];
|
|
||||||
|
|
||||||
for await (const chunk of stream) {
|
|
||||||
chunks.push(chunk instanceof Buffer ? chunk : Buffer.from(chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.concat(chunks);
|
|
||||||
}
|
|
Loading…
Reference in New Issue