UNPKG

thenavisapp

Version:

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

504 lines (396 loc) 13 kB
import process from 'node:process'; import {Buffer} from 'node:buffer'; import fs from 'node:fs'; import {Agent as HttpAgent} from 'node:http'; import stream, {Readable as ReadableStream, Writable} from 'node:stream'; import {pipeline as streamPipeline} from 'node:stream/promises'; import {Readable as Readable2} from 'readable-stream'; import test from 'ava'; import type {Handler} from 'express'; import getStream from 'get-stream'; import {pEvent} from 'p-event'; import FormData from 'form-data'; import is from '@sindresorhus/is'; import delay from 'delay'; import got, {HTTPError, RequestError} from '../source/index.js'; import withServer from './helpers/with-server.js'; const defaultHandler: Handler = (_request, response) => { response.writeHead(200, { unicorn: 'rainbow', 'content-encoding': 'gzip', }); response.end(Buffer.from('H4sIAAAAAAAA/8vPBgBH3dx5AgAAAA==', 'base64')); // 'ok' }; const redirectHandler: Handler = (_request, response) => { response.writeHead(302, { location: '/', }); response.end(); }; const postHandler: Handler = async (request, response) => { await streamPipeline(request, response); }; const errorHandler: Handler = (_request, response) => { response.statusCode = 404; response.end(); }; const headersHandler: Handler = (request, response) => { response.end(JSON.stringify(request.headers)); }; const infiniteHandler: Handler = (_request, response) => { response.write('foobar'); }; test('reusedSocket getter', withServer, async (t, server, got) => { server.get('/', defaultHandler); const agent = new HttpAgent({keepAlive: true}); const stream = got.stream('', {agent: {http: agent}}); t.is(stream.reusedSocket, undefined); await pEvent(stream, 'response'); stream.resume(); await pEvent(stream, 'end'); t.false(stream.reusedSocket); const secondStream = got.stream('', {agent: {http: agent}}); secondStream.resume(); await pEvent(secondStream, 'end'); t.true(secondStream.reusedSocket); }); test('`options.responseType` is ignored', withServer, async (t, server, got) => { server.get('/', defaultHandler); await t.notThrowsAsync(getStream(got.stream({responseType: 'json'}))); }); test('returns readable stream', withServer, async (t, server, got) => { server.get('/', defaultHandler); const data = await getStream(got.stream('')); t.is(data, 'ok'); }); test('returns writeable stream', withServer, async (t, server, got) => { server.post('/', postHandler); const stream = got.stream.post(''); const promise = getStream(stream); stream.end('wow'); t.is(await promise, 'wow'); }); test('does not throw if using stream and passing a json option', withServer, async (t, server, got) => { server.post('/', postHandler); await t.notThrowsAsync(getStream(got.stream.post({json: {}}))); }); test('does not throw if using stream and passing a form option', withServer, async (t, server, got) => { server.post('/', postHandler); await t.notThrowsAsync(getStream(got.stream.post({form: {}}))); }); test('has request event', withServer, async (t, server, got) => { server.get('/', defaultHandler); const stream = got.stream(''); const request = await pEvent(stream, 'request'); t.truthy(request); t.is(request.method, 'GET'); await getStream(stream); }); test('has redirect event', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.get('/redirect', redirectHandler); const stream = got.stream('redirect'); const [, {headers}] = await pEvent(stream, 'redirect', {multiArgs: true}); t.is(headers.location, '/'); await getStream(stream); }); test('has response event', withServer, async (t, server, got) => { server.get('/', defaultHandler); const {statusCode} = await pEvent(got.stream(''), 'response'); t.is(statusCode, 200); }); test('has error event', withServer, async (t, server, got) => { server.get('/', errorHandler); const stream = got.stream(''); await t.throwsAsync(pEvent(stream, 'response'), { instanceOf: HTTPError, message: 'Response code 404 (Not Found)', }); }); test('has error event #2', async t => { const stream = got.stream('http://doesntexist'); try { await pEvent(stream, 'response'); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); } }); test('has response event if `options.throwHttpErrors` is false', withServer, async (t, server, got) => { server.get('/', errorHandler); const {statusCode} = await pEvent(got.stream({throwHttpErrors: false}), 'response'); t.is(statusCode, 404); }); test('accepts `options.body` as a Stream', withServer, async (t, server, got) => { server.post('/', postHandler); const stream = got.stream.post({body: ReadableStream.from('wow')}); t.is(await getStream(stream), 'wow'); }); test('redirect response contains old url', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.get('/redirect', redirectHandler); const {requestUrl} = await pEvent(got.stream('redirect'), 'response'); t.is(requestUrl.toString(), `${server.url}/redirect`); }); test('check for pipe method', withServer, (t, server, got) => { server.get('/', defaultHandler); const stream = got.stream(''); t.true(is.function_(stream.pipe)); t.true(is.function_(stream.on('foobar', () => {}).pipe)); stream.destroy(); }); test('piping works', withServer, async (t, server, got) => { server.get('/', defaultHandler); t.is(await getStream(got.stream('')), 'ok'); t.is(await getStream(got.stream('').on('foobar', () => {})), 'ok'); }); test('proxying headers works', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.get('/proxy', async (_request, response) => { await streamPipeline( got.stream(''), response, ); }); const {headers, body} = await got('proxy'); t.is(headers.unicorn, 'rainbow'); t.is(headers['content-encoding'], undefined); t.is(body, 'ok'); }); test('piping server request to Got proxies also headers', withServer, async (t, server, got) => { server.get('/', headersHandler); server.get('/proxy', async (request, response) => { await streamPipeline( request, got.stream(''), response, ); }); const {foo}: {foo: string} = await got('proxy', { headers: { foo: 'bar', }, }).json(); t.is(foo, 'bar'); }); test('skips proxying headers after server has sent them already', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.get('/proxy', async (_request, response) => { response.writeHead(200); await streamPipeline( got.stream(''), response, ); }); const {headers} = await got('proxy'); t.is(headers.unicorn, undefined); }); test('proxies `content-encoding` header when `options.decompress` is false', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.get('/proxy', async (_request, response) => { await streamPipeline( got.stream({decompress: false}), response, ); }); const {headers} = await got('proxy', {decompress: false}); t.is(headers.unicorn, 'rainbow'); t.is(headers['content-encoding'], 'gzip'); }); { const nodejsMajorVersion = Number(process.versions.node.split('.')[0]); const testFn = nodejsMajorVersion < 14 ? test.failing : test; testFn('destroying got.stream() destroys the request - `request` event', withServer, async (t, server, got) => { server.get('/', defaultHandler); const stream = got.stream(''); const request = await pEvent(stream, 'request'); stream.destroy(); t.truthy(request.destroyed); }); testFn('destroying got.stream() destroys the request - `response` event', withServer, async (t, server, got) => { server.get('/', (_request, response) => { response.write('hello'); }); const stream = got.stream(''); const request = await pEvent(stream, 'request'); await pEvent(stream, 'response'); stream.destroy(); t.truthy(request.destroyed); }); } test('piping to got.stream.put()', withServer, async (t, server, got) => { server.get('/', defaultHandler); server.put('/post', postHandler); await t.notThrowsAsync(async () => { const stream = got.stream.put('post'); await streamPipeline( got.stream(''), stream, ); await getStream(stream); }); }); // See https://github.com/nodejs/node/issues/35237 // eslint-disable-next-line ava/no-skip-test test.skip('no unhandled body stream errors', async t => { const body = new FormData(); body.append('upload', fs.createReadStream('/bin/sh')); await t.throwsAsync(got.post(`https://offlinesite${Date.now()}.com`, { body, }), { code: 'ENOTFOUND', }); }); test('works with pipeline', async t => { await t.throwsAsync(streamPipeline( new ReadableStream({ read() { this.push(null); }, }), got.stream.put('http://localhost:7777'), ), { instanceOf: RequestError, // TODO: Find out why it has no message. // message: /^connect ECONNREFUSED (127\.0\.0\.1|::1):7777$/, }); }); test('errors have body', withServer, async (t, server, got) => { server.get('/', (_request, response) => { response.setHeader('set-cookie', 'foo=bar'); response.end('yay'); }); const error = await t.throwsAsync<RequestError>(getStream(got.stream('', { cookieJar: { async setCookie() { throw new Error('snap'); }, getCookieString: async () => '', }, }))); t.is(error?.message, 'snap'); t.is(error?.response?.body, 'yay'); }); test('pipe can send modified headers', withServer, async (t, server, got) => { server.get('/foobar', (_request, response) => { response.setHeader('foo', 'bar'); response.end(); }); server.get('/', (_request, response) => { got.stream('foobar').on('response', response => { response.headers.foo = 'boo'; }).pipe(response); }); const {headers} = await got(''); t.is(headers.foo, 'boo'); }); test('the socket is alive on a successful pipeline', withServer, async (t, server, got) => { const payload = 'ok'; server.get('/', (_request, response) => { response.end(payload); }); const gotStream = got.stream(''); t.is(gotStream.socket, undefined); const receiver = new stream.PassThrough(); await streamPipeline(gotStream, receiver); t.is(await getStream(receiver), payload); t.truthy(gotStream.socket); t.false(gotStream.socket!.destroyed); }); test('async iterator works', withServer, async (t, server, got) => { const payload = 'ok'; server.get('/', (_request, response) => { response.end(payload); }); const gotStream = got.stream(''); const chunks = []; for await (const chunk of gotStream) { chunks.push(chunk); } t.is(Buffer.concat(chunks).toString(), payload); }); test('destroys only once', async t => { const stream = got.stream('https://example.com'); stream.destroy(); stream.destroy(new Error('oh no')); let errored = false; stream.once('error', () => { errored = true; }); await delay(1); t.false(errored); }); test('does not accept unreadable stream as body', withServer, async (t, server, got) => { server.post('/', (_request, _response) => {}); const body = new ReadableStream(); body.push(null); body.resume(); await pEvent(body, 'end'); const request = got.post({body}); await t.throwsAsync(request); // TODO: Add assert message above. }); test('accepts readable-stream as body', withServer, async (t, server, got) => { server.post('/', (request, response) => { request.pipe(response); }); const body = new Readable2({ read() { this.push('ok'); this.push(null); }, }); const response = await got.post({ // We need to cast body as any, // because @types/readable-stream has incorrect types // and causes a lot of errors. body: body as any, }); t.is(response.body, 'ok'); }); test('prevents `Cannot call end` error', async t => { const stream = got.stream('https://example.com', { request: () => new Writable({ final() {}, }) as any, timeout: { request: 1, }, }); const error: RequestError = await pEvent(stream, 'error'); t.is(error.code, 'ETIMEDOUT'); }); if (Number.parseInt(process.versions.node.split('.')[0]!, 10) <= 12) { test('does not emit end event on error', withServer, async (t, server, got) => { server.get('/', infiniteHandler); await t.notThrowsAsync(new Promise((resolve, reject) => { got.stream({ timeout: { request: 100, }, hooks: { beforeError: [ async error => { await new Promise(resolve => { setTimeout(resolve, 50); }); return error; }, ], }, }).once('end', () => { reject(new Error('Stream has ended before erroring')); }).once('error', resolve).resume(); })); }); } // Test only on Linux const testFn = process.platform === 'linux' ? test : test.skip; testFn('it sends a body of file with size on stat = 0', withServer, async (t, server, got) => { server.post('/', async (request, response) => { response.end(await getStream(request)); }); const response = await got.post({ body: fs.createReadStream('/proc/cpuinfo'), }); t.truthy(response.body); });