Skip to content

Commit

Permalink
Add support for relative URLs and searchParams even in non-browsers (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
sholladay committed Jul 17, 2020
1 parent 95e7fd7 commit c9e5206
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 28 deletions.
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ class Ky {
this.request = new globals.Request(this._input, this._options);

if (this._options.searchParams) {
const url = new URL(this.request.url);
url.search = new URLSearchParams(this._options.searchParams);
const searchParams = '?' + new URLSearchParams(this._options.searchParams).toString();
const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams);

// To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
if (((supportsFormData && this._options.body instanceof globals.FormData) || this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
"form-data": "^3.0.0",
"node-fetch": "^2.5.0",
"nyc": "^15.0.0",
"puppeteer": "^3.0.4",
"puppeteer": "^5.1.0",
"rollup": "^2.10.2",
"tsd": "^0.11.0",
"tsd": "^0.13.1",
"xo": "^0.25.3"
},
"sideEffects": false,
Expand Down
53 changes: 30 additions & 23 deletions test/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const pBody = util.promisify(body);

test('prefixUrl option', withPage, async (t, page) => {
const server = await createTestServer();

server.get('/', (request, response) => {
response.end('zebra');
});
Expand All @@ -19,21 +20,23 @@ test('prefixUrl option', withPage, async (t, page) => {
await page.goto(server.url);
await page.addScriptTag({path: './umd.js'});

await t.throwsAsync(async () => {
return page.evaluate(() => {
await t.throwsAsync(
page.evaluate(() => {
return window.ky('/foo', {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();
}),
{message: /`input` must not begin with a slash when using `prefixUrl`/}
);

const results = await page.evaluate(url => {
return Promise.all([
window.ky(`${url}/api/unicorn`).text(),
window.ky(`${url}/api/unicorn`, {prefixUrl: null}).text(),
window.ky('api/unicorn', {prefixUrl: url}).text(),
window.ky('api/unicorn', {prefixUrl: `${url}/`}).text()
]);
}, server.url);
t.is(unprefixed, 'rainbow');

const prefixed = await page.evaluate(prefixUrl => {
return window.ky('api/unicorn', {prefixUrl}).text();
}, server.url);
t.is(prefixed, 'rainbow');
t.deepEqual(results, ['rainbow', 'rainbow', 'rainbow', 'rainbow']);

await server.close();
});
Expand Down Expand Up @@ -96,7 +99,7 @@ test('onDownloadProgress works', withPage, async (t, page) => {

server.get('/', (request, response) => {
response.writeHead(200, {
'content-length': 4
'content-length': '4'
});

response.write('me');
Expand Down Expand Up @@ -289,6 +292,8 @@ test('headers are preserved when input is a Request and there are searchParams i
});

test('retry with body', withPage, async (t, page) => {
t.plan(4);

let requestCount = 0;

const server = await createTestServer();
Expand All @@ -297,22 +302,24 @@ test('retry with body', withPage, async (t, page) => {
});
server.put('/test', async (request, response) => {
requestCount++;
await pBody(request);
t.is(await pBody(request), 'foo');
response.sendStatus(502);
});

await page.goto(server.url);
await page.addScriptTag({path: './umd.js'});

const error = await page.evaluate(url => {
const request = window.ky(url + '/test', {
body: 'foo',
method: 'PUT',
retry: 2
}).text();
return request.catch(error_ => error_.toString());
}, server.url);
t.is(error, 'HTTPError: Bad Gateway');
await t.throwsAsync(
page.evaluate(async url => {
return window.ky(url + '/test', {
body: 'foo',
method: 'PUT',
retry: 2
});
}, server.url),
{message: /HTTPError: Bad Gateway/}
);

t.is(requestCount, 2);

await server.close();
Expand Down
18 changes: 18 additions & 0 deletions test/fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import test from 'ava';
import ky from '..';

test.serial('relative URLs are passed to fetch unresolved', async t => {
const originalFetch = global.fetch;
global.fetch = async input => {
t.true(input.url.startsWith('/'));
return new Response(input.url);
};

t.is(await ky('/unicorn').text(), '/unicorn');
t.is(await ky('/unicorn', {searchParams: {foo: 'bar'}}).text(), '/unicorn?foo=bar');
t.is(await ky('/unicorn#hash', {searchParams: 'foo'}).text(), '/unicorn?foo=#hash');
t.is(await ky('/unicorn?old', {searchParams: 'new'}).text(), '/unicorn?new=');
t.is(await ky('/unicorn?old#hash', {searchParams: 'new'}).text(), '/unicorn?new=#hash');
t.is(await ky('unicorn', {prefixUrl: '/api/'}).text(), '/api/unicorn');
global.fetch = originalFetch;
});
1 change: 0 additions & 1 deletion test/helpers/with-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export default async function withPage(t, run) {
try {
await run(t, page);
} finally {
await page.close();
await browser.close();
}
}

0 comments on commit c9e5206

Please sign in to comment.