From 7c1d37146197508a11e4dcff432682f199e38cc7 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 3 Feb 2020 02:05:23 +0700 Subject: [PATCH] Require Node.js 10 --- package.json | 14 ++++++------- readme.md | 14 ++----------- test/browser.js | 2 +- test/hooks.js | 30 +++++++++++++++++----------- test/main.js | 50 ++++++++++++++++++++++++++++++++++------------ test/prefix-url.js | 4 +++- test/retry.js | 50 +++++++++++++++++++++++++++++++++------------- 7 files changed, 103 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index eacf153d..49f70b48 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "url": "sindresorhus.com" }, "engines": { - "node": ">=8" + "node": ">=10" }, "scripts": { "build": "rollup index.js --format=umd --name=ky --file=umd.js", @@ -48,17 +48,17 @@ ], "devDependencies": { "abort-controller": "^3.0.0", - "ava": "^1.4.1", + "ava": "^3.2.0", "body": "^5.1.0", - "codecov": "^3.4.0", + "codecov": "^3.6.4", "create-test-server": "2.1.1", "delay": "^4.1.0", "esm": "^3.2.22", "form-data": "^3.0.0", "node-fetch": "^2.5.0", - "nyc": "^14.1.1", - "puppeteer": "^1.15.0", - "rollup": "^1.27.0", + "nyc": "^15.0.0", + "puppeteer": "^2.1.0", + "rollup": "^1.31.0", "tsd": "^0.11.0", "xo": "^0.25.3" }, @@ -72,8 +72,6 @@ ] }, "ava": { - "babel": false, - "compileEnhancements": false, "require": [ "esm", "./test/_require" diff --git a/readme.md b/readme.md index 5844d8a3..5ed1c83a 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,6 @@ Ky targets [modern browsers](#browser-support) and [Deno](https://github.com/den It's just a tiny file with no dependencies. - ## Benefits over plain `fetch` - Simpler API @@ -31,7 +30,6 @@ It's just a tiny file with no dependencies. - Instances with custom defaults - Hooks - ## Install ``` @@ -48,7 +46,6 @@ $ npm install ky - [jsdelivr](https://www.jsdelivr.com/package/npm/ky) - [unpkg](https://unpkg.com/ky) - ## Usage ```js @@ -101,7 +98,6 @@ const ky = require('ky/umd'); With the UMD version, it's also easy to use `ky` [without a bundler](#how-do-i-use-this-without-a-bundler-like-webpack) or module system. - ## API ### ky(input, options?) @@ -411,10 +407,9 @@ import ky from 'ky'; })(); ``` - ## Tips -### Sending Form Data +### Sending form data Sending form data in Ky is identical to `fetch`. Just pass a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instance to the `body` option. The `Content-Type` header will be automatically set to `multipart/form-data`. @@ -479,7 +474,6 @@ setTimeout(() => { })(); ``` - ## FAQ #### How do I use this in Node.js? @@ -543,23 +537,19 @@ It's just a random short npm package name I managed to get. It does, however, ha > A form of text-able slang, KY is an abbreviation for 空気読めない (kuuki yomenai), which literally translates into “cannot read the air.” It's a phrase applied to someone who misses the implied meaning. - ## Browser support The latest version of Chrome, Firefox, and Safari. - ## Node.js support -Ky requires Node.js 10 or later, but it indicates Node.js 8 in package.json so you can use it with Node.js 8 by polyfilling the globals without having Yarn fail on install. However, you should just use [`ky-universal`](https://github.com/sindresorhus/ky-universal). - +Polyfill the needed browser global or just use [`ky-universal`](https://github.com/sindresorhus/ky-universal). ## Related - [ky-universal](https://github.com/sindresorhus/ky-universal) - Use Ky in both Node.js and browsers - [got](https://github.com/sindresorhus/got) - Simplified HTTP requests for Node.js - ## Maintainers - [Sindre Sorhus](https://github.com/sindresorhus) diff --git a/test/browser.js b/test/browser.js index 86508a62..26ee773f 100644 --- a/test/browser.js +++ b/test/browser.js @@ -22,7 +22,7 @@ test('prefixUrl option', withPage, async (t, page) => { return page.evaluate(() => { return window.ky('/foo', {prefixUrl: '/'}); }); - }, /`input` must not begin with a slash when using `prefixUrl`/); + }, {message: /`input` must not begin with a slash when using `prefixUrl`/}); const unprefixed = await page.evaluate(url => { return window.ky(`${url}/api/unicorn`).text(); diff --git a/test/hooks.js b/test/hooks.js index 8bbc0d16..a7abd8e1 100644 --- a/test/hooks.js +++ b/test/hooks.js @@ -427,13 +427,16 @@ test('catches beforeRetry thrown errors', async t => { const errorString = 'oops'; const error = new Error(errorString); - await t.throwsAsync(ky.get(server.url, { - hooks: { - beforeRetry: [() => { - throw error; - }] - } - }), errorString); + await t.throwsAsync( + ky.get(server.url, { + hooks: { + beforeRetry: [() => { + throw error; + }] + } + }), + {message: errorString} + ); }); test('catches beforeRetry promise rejections', async t => { @@ -453,11 +456,14 @@ test('catches beforeRetry promise rejections', async t => { const errorString = 'oops'; const error = new Error(errorString); - await t.throwsAsync(ky.get(server.url, { - hooks: { - beforeRetry: [() => Promise.reject(error)] - } - }), errorString); + await t.throwsAsync( + ky.get(server.url, { + hooks: { + beforeRetry: [() => Promise.reject(error)] + } + }), + {message: errorString} + ); }); test('hooks beforeRequest returning Response skips HTTP Request', async t => { diff --git a/test/main.js b/test/main.js index 72bab8e3..db794d6b 100644 --- a/test/main.js +++ b/test/main.js @@ -111,19 +111,29 @@ test('POST JSON', async t => { test('cannot use `body` option with GET or HEAD method', t => { t.throws(() => { ky.get('https://example.com', {body: 'foobar'}); - }, 'Request with GET/HEAD method cannot have body'); + }, { + message: 'Request with GET/HEAD method cannot have body' + }); + t.throws(() => { ky.head('https://example.com', {body: 'foobar'}); - }, 'Request with GET/HEAD method cannot have body'); + }, { + message: 'Request with GET/HEAD method cannot have body' + }); }); test('cannot use `json` option with GET or HEAD method', t => { t.throws(() => { ky.get('https://example.com', {json: {}}); - }, 'Request with GET/HEAD method cannot have body'); + }, { + message: 'Request with GET/HEAD method cannot have body' + }); + t.throws(() => { ky.head('https://example.com', {json: {}}); - }, 'Request with GET/HEAD method cannot have body'); + }, { + message: 'Request with GET/HEAD method cannot have body' + }); }); test('`json` option overrides the `body` option', async t => { @@ -215,7 +225,7 @@ test('.json() with 200 response and empty body', async t => { response.status(200).end(); }); - await t.throwsAsync(ky(server.url).json(), /Unexpected end of JSON input/); + await t.throwsAsync(ky(server.url).json(), {message: /Unexpected end of JSON input/}); await server.close(); }); @@ -246,7 +256,11 @@ test('timeout option', async t => { response.end(fixture); }); - await t.throwsAsync(ky(server.url, {timeout: 500}).text(), ky.TimeoutError); + await t.throwsAsync( + ky(server.url, {timeout: 500}).text(), + {instanceOf: ky.TimeoutError} + ); + t.is(requestCount, 1); await server.close(); @@ -262,7 +276,10 @@ test('timeout:false option', async t => { response.end(fixture); }); - await t.notThrowsAsync(ky(server.url, {timeout: false}).text(), ky.TimeoutError); + await t.notThrowsAsync( + ky(server.url, {timeout: false}).text() + ); + t.is(requestCount, 1); await server.close(); @@ -278,7 +295,14 @@ test('invalid timeout option', async t => { // #117 response.end(fixture); }); - await t.throwsAsync(ky(server.url, {timeout: 21474836470}).text(), RangeError, 'The `timeout` option cannot be greater than 2147483647'); + await t.throwsAsync( + ky(server.url, {timeout: 21474836470}).text(), + { + instanceOf: RangeError, + message: 'The `timeout` option cannot be greater than 2147483647' + } + ); + t.is(requestCount, 0); await server.close(); @@ -333,8 +357,7 @@ test('throwHttpErrors option', async t => { }); await t.notThrowsAsync( - ky.get(server.url, {throwHttpErrors: false}).text(), - /Internal Server Error/ + ky.get(server.url, {throwHttpErrors: false}).text() ); await server.close(); @@ -347,8 +370,7 @@ test('throwHttpErrors option with POST', async t => { }); await t.notThrowsAsync( - ky.post(server.url, {throwHttpErrors: false}).text(), - /Internal Server Error/ + ky.post(server.url, {throwHttpErrors: false}).text() ); await server.close(); @@ -501,7 +523,9 @@ test('supports Request instance as input', async t => { test('throws when input is not a string, URL, or Request', t => { t.throws(() => { ky.get(0); - }, '`input` must be a string, URL, or Request'); + }, { + message: '`input` must be a string, URL, or Request' + }); }); test('options override Request instance method', async t => { diff --git a/test/prefix-url.js b/test/prefix-url.js index f6caa27a..49502498 100644 --- a/test/prefix-url.js +++ b/test/prefix-url.js @@ -25,7 +25,9 @@ test('prefixUrl option', async t => { t.throws(() => { ky('/unicorn', {prefixUrl: `${server.url}/api`}); - }, '`input` must not begin with a slash when using `prefixUrl`'); + }, { + message: '`input` must not begin with a slash when using `prefixUrl`' + }); await server.close(); }); diff --git a/test/retry.js b/test/retry.js index 30d793cb..29736450 100644 --- a/test/retry.js +++ b/test/retry.js @@ -59,7 +59,7 @@ test('only on defined status codes', async t => { } }); - await t.throwsAsync(ky(server.url).text(), /Bad Request/); + await t.throwsAsync(ky(server.url).text(), {message: /Bad Request/}); await server.close(); }); @@ -78,7 +78,7 @@ test('not on POST', async t => { } }); - await t.throwsAsync(ky.post(server.url).text(), /Internal Server Error/); + await t.throwsAsync(ky.post(server.url).text(), {message: /Internal Server Error/}); await server.close(); }); @@ -139,7 +139,7 @@ test('doesn\'t retry on 413 without Retry-After header', async t => { response.sendStatus(413); }); - await t.throwsAsync(ky(server.url).text(), /Payload Too Large/); + await t.throwsAsync(ky(server.url).text(), {message: /Payload Too Large/}); t.is(requestCount, 1); await ky(server.url, {throwHttpErrors: false}).text(); t.is(requestCount, 2); @@ -162,7 +162,9 @@ test('respect number of retries', async t => { limit: 3 } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 3); @@ -191,7 +193,9 @@ test('respect retry methods', async t => { methods: ['get'] } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 1); @@ -203,7 +207,9 @@ test('respect retry methods', async t => { methods: ['get'] } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 3); @@ -231,7 +237,9 @@ test('respect maxRetryAfter', async t => { maxRetryAfter: 100 } }).text(), - /Payload Too Large/ + { + message: /Payload Too Large/ + } ); t.is(requestCount, 1); @@ -243,7 +251,9 @@ test('respect maxRetryAfter', async t => { maxRetryAfter: 2000 } }).text(), - /Payload Too Large/ + { + message: /Payload Too Large/ + } ); t.is(requestCount, 5); @@ -261,7 +271,9 @@ test('retry - can provide retry as number', async t => { await t.throwsAsync( ky(server.url, {retry: 5}).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 5); @@ -286,7 +298,9 @@ test('doesn\'t retry on 413 with empty statusCodes and methods', async t => { methods: [] } }).text(), - /Payload Too Large/ + { + message: /Payload Too Large/ + } ); t.is(requestCount, 1); @@ -310,7 +324,9 @@ test('doesn\'t retry on 413 with empty methods', async t => { methods: [] } }).text(), - /Payload Too Large/ + { + message: /Payload Too Large/ + } ); t.is(requestCount, 1); @@ -334,7 +350,9 @@ test('does retry on 408 with methods provided as array', async t => { methods: ['get'] } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 4); @@ -358,7 +376,9 @@ test('does retry on 408 with statusCodes provided as array', async t => { statusCodes: [408] } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 4); @@ -381,7 +401,9 @@ test('doesn\'t retry when retry.limit is set to 0', async t => { limit: 0 } }).text(), - /Request Timeout/ + { + message: /Request Timeout/ + } ); t.is(requestCount, 1);