Skip to content

Commit 070a456

Browse files
feat: add json option to http (#34)
- uses aegir test helps - updates deps - adds more tests Co-authored-by: Alex Potsides <alex@achingbrain.net>
1 parent 34dc3c9 commit 070a456

14 files changed

+71
-108
lines changed

.aegir.js

Lines changed: 9 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,21 @@
11
'use strict'
22

3-
const { promisify } = require('util')
4-
const http = require('http')
5-
const url = require('url')
6-
const querystring = require('querystring')
3+
const EchoServer = require('aegir/utils/echo-server')
4+
const { format } =require('iso-url')
75

8-
const echoServer = async (port = 3000) => {
9-
const server = http.createServer()
10-
11-
server.on('request', (request, response) => {
12-
try {
13-
14-
const uri = url.parse(request.url)
15-
const qs = uri.query ? querystring.parse(uri.query) : {}
16-
const status = qs.status || 200
17-
const contentType = qs.contentType || 'text/plain'
18-
19-
const headers = {
20-
'Access-Control-Allow-Origin': '*'
21-
}
22-
23-
if (qs.body) {
24-
headers['Content-Type'] = contentType
25-
headers['Content-Length'] = qs.body.length
26-
}
27-
28-
response.writeHead(status, headers)
29-
30-
if (qs.body) {
31-
response.end(qs.body)
32-
} else {
33-
request.pipe(response)
34-
}
35-
36-
} catch (err) {
37-
console.error(err)
38-
}
39-
})
40-
41-
await promisify(server.listen.bind(server))(port)
42-
43-
return {
44-
stop: promisify(server.close.bind(server))
45-
}
46-
}
47-
48-
let echo
6+
let echo = new EchoServer()
497

508
module.exports = {
519
hooks: {
5210
pre: async () => {
53-
echo = await echoServer()
11+
const server = await echo.start()
12+
const { address, port } = server.server.address()
13+
return {
14+
env: { ECHO_SERVER : format({ protocol: 'http:', hostname: address, port })}
15+
}
5416
},
5517
post: async () => {
5618
await echo.stop()
5719
}
5820
}
59-
}
21+
}

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,13 @@
4040
"iso-url": "^0.4.7",
4141
"it-glob": "0.0.7",
4242
"merge-options": "^2.0.0",
43-
"nanoid": "^2.1.11",
43+
"nanoid": "^3.1.3",
4444
"node-fetch": "^2.6.0",
4545
"stream-to-it": "^0.2.0"
4646
},
4747
"devDependencies": {
48-
"aegir": "^21.4.2",
49-
"chai": "^4.2.0",
50-
"chai-as-promised": "^7.1.1",
48+
"aegir": "^21.8.0",
5149
"delay": "^4.3.0",
52-
"dirty-chai": "^2.0.1",
5350
"it-all": "^1.0.1",
5451
"it-drain": "^1.0.0",
5552
"it-last": "^1.0.1",

src/http.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ const fetch = require('node-fetch')
55
const merge = require('merge-options')
66
const { URL, URLSearchParams } = require('iso-url')
77
const TextDecoder = require('./text-encoder')
8-
const Request = require('./globalthis').Request
98
const AbortController = require('abort-controller')
109

10+
const Request = fetch.Request
11+
const Headers = fetch.Headers
12+
1113
class TimeoutError extends Error {
1214
constructor () {
1315
super('Request timed out')
@@ -49,6 +51,7 @@ const timeout = (promise, ms, abortController) => {
4951
}
5052

5153
const defaults = {
54+
headers: {},
5255
throwHttpErrors: true,
5356
credentials: 'same-origin',
5457
transformSearchParams: p => p
@@ -57,6 +60,7 @@ const defaults = {
5760
/**
5861
* @typedef {Object} APIOptions - creates a new type named 'SpecialType'
5962
* @prop {any} [body] - Request body
63+
* @prop {Object} [json] - JSON shortcut
6064
* @prop {string} [method] - GET, POST, PUT, DELETE, etc.
6165
* @prop {string} [base] - The base URL to use in case url is a relative URL
6266
* @prop {Headers|Record<string, string>} [headers] - Request header.
@@ -78,6 +82,7 @@ class HTTP {
7882
constructor (options = {}) {
7983
/** @type {APIOptions} */
8084
this.opts = merge(defaults, options)
85+
this.opts.headers = new Headers(options.headers)
8186

8287
// connect internal abort to external
8388
this.abortController = new AbortController()
@@ -101,6 +106,7 @@ class HTTP {
101106
async fetch (resource, options = {}) {
102107
/** @type {APIOptions} */
103108
const opts = merge(this.opts, options)
109+
opts.headers = new Headers(opts.headers)
104110

105111
// validate resource type
106112
if (typeof resource !== 'string' && !(resource instanceof URL || resource instanceof Request)) {
@@ -127,6 +133,11 @@ class HTTP {
127133
url.search = opts.transformSearchParams(new URLSearchParams(opts.searchParams))
128134
}
129135

136+
if (opts.json !== undefined) {
137+
opts.body = JSON.stringify(opts.json)
138+
opts.headers.set('content-type', 'application/json')
139+
}
140+
130141
const response = await timeout(fetch(url, opts), opts.timeout, this.abortController)
131142

132143
if (!response.ok && opts.throwHttpErrors) {

src/temp-dir.browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const nanoid = require('nanoid')
3+
const { nanoid } = require('nanoid')
44

55
/**
66
* Temporary folder

src/temp-dir.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const fs = require('fs')
44
const os = require('os')
55
const path = require('path')
6-
const nanoid = require('nanoid')
6+
const { nanoid } = require('nanoid')
77

88
/**
99
* Temporary folder

test/env.spec.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
4+
const { expect } = require('aegir/utils/chai')
65
const env = require('../src/env')
76

8-
chai.use(dirtyChai)
9-
const expect = chai.expect
10-
117
describe('env', function () {
128
it('isElectron should have the correct value in each env', function () {
139
switch (process.env.AEGIR_RUNNER) {

test/files/format-mode.spec.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
4+
const { expect } = require('aegir/utils/chai')
65
const formatMode = require('../../src/files/format-mode')
76

8-
chai.use(dirtyChai)
9-
const expect = chai.expect
10-
117
describe('format-mode', function () {
128
it('formats mode for directories', function () {
139
expect(formatMode(parseInt('0777', 8), true)).to.equal('drwxrwxrwx')

test/files/format-mtime.spec.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
4+
const { expect } = require('aegir/utils/chai')
65
const formatMtime = require('../../src/files/format-mtime')
76

8-
chai.use(dirtyChai)
9-
const expect = chai.expect
10-
117
describe('format-mtime', function () {
128
it('formats mtime', function () {
139
expect(formatMtime({ secs: 15768000, nsecs: 0 })).to.include('1970')

test/files/glob-source.spec.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
6-
const chaiAsPromised = require('chai-as-promised')
4+
const { expect } = require('aegir/utils/chai')
75
const globSource = require('../../src/files/glob-source')
86
const all = require('it-all')
97
const path = require('path')
@@ -12,10 +10,6 @@ const {
1210
} = require('../../src/env')
1311
const fs = require('fs')
1412

15-
chai.use(dirtyChai)
16-
chai.use(chaiAsPromised)
17-
const expect = chai.expect
18-
1913
function fixture (file) {
2014
return path.resolve(path.join(__dirname, '..', 'fixtures', file))
2115
}

test/files/normalise-input.spec.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
4+
const { expect, assert } = require('aegir/utils/chai')
65
const normalise = require('../../src/files/normalise-input')
76
const { supportsFileReader } = require('../../src/supports')
87
const { Buffer } = require('buffer')
98
const all = require('it-all')
109
const globalThis = require('../../src/globalthis')
1110

12-
chai.use(dirtyChai)
13-
const expect = chai.expect
14-
1511
const STRING = () => 'hello world'
1612
const BUFFER = () => Buffer.from(STRING())
1713
const ARRAY = () => Array.from(BUFFER())
@@ -36,7 +32,7 @@ async function verifyNormalisation (input) {
3632
expect(input.length).to.equal(1)
3733

3834
if (!input[0].content[Symbol.asyncIterator] && !input[0].content[Symbol.iterator]) {
39-
chai.assert.fail('Content should have been an iterable or an async iterable')
35+
assert.fail('Content should have been an iterable or an async iterable')
4036
}
4137

4238
expect(await all(input[0].content)).to.deep.equal([BUFFER()])

test/files/url-source.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/* eslint-env mocha */
44

5-
const { expect } = require('../utils/chai')
5+
const { expect } = require('aegir/utils/chai')
66
const all = require('it-all')
77
const urlSource = require('../../src/files/url-source')
88
const last = require('it-last')
@@ -11,7 +11,7 @@ const { Buffer } = require('buffer')
1111
describe('url-source', function () {
1212
it('can get url content', async function () {
1313
const content = 'foo'
14-
const file = await last(urlSource(`http://localhost:3000?body=${content}`))
14+
const file = await last(urlSource(`${process.env.ECHO_SERVER}/download?data=${content}`))
1515

1616
await expect(all(file.content)).to.eventually.deep.equal([Buffer.from(content)])
1717
})

test/http.spec.js

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const { expect } = require('./utils/chai')
4+
const { expect } = require('aegir/utils/chai')
55
const HTTP = require('../src/http')
66
const toStream = require('it-to-stream')
77
const delay = require('delay')
@@ -13,15 +13,43 @@ const { Buffer } = require('buffer')
1313

1414
describe('http', function () {
1515
it('makes a GET request', async function () {
16-
const res = HTTP.get('http://localhost:3000')
16+
const req = await HTTP.get(`${process.env.ECHO_SERVER}/echo/query?test=one`)
17+
const rsp = await req.json()
18+
expect(rsp).to.be.deep.eq({ test: 'one' })
19+
})
20+
21+
it('makes a GET request with redirect', async function () {
22+
const req = await HTTP.get(`${process.env.ECHO_SERVER}/redirect?to=${encodeURI(`${process.env.ECHO_SERVER}/echo/query?test=one`)}`)
23+
const rsp = await req.json()
24+
expect(rsp).to.be.deep.eq({ test: 'one' })
25+
})
26+
27+
it('makes a JSON request', async () => {
28+
const req = await HTTP.post(`${process.env.ECHO_SERVER}/echo`, {
29+
json: {
30+
test: 2
31+
}
32+
})
33+
34+
const out = await req.text()
35+
expect(out).to.be.eq('{"test":2}')
36+
})
37+
38+
it('makes a DELETE request', async () => {
39+
const req = await HTTP.delete(`${process.env.ECHO_SERVER}/echo`, {
40+
json: {
41+
test: 2
42+
}
43+
})
1744

18-
await expect(res).to.eventually.be.fulfilled()
45+
const out = await req.text()
46+
expect(out).to.be.eq('{"test":2}')
1947
})
2048

2149
it('allow async aborting', async function () {
2250
const controller = new AbortController()
2351

24-
const res = HTTP.get('http://localhost:3000', {
52+
const res = HTTP.get(process.env.ECHO_SERVER, {
2553
signal: controller.signal
2654
})
2755
controller.abort()
@@ -30,7 +58,7 @@ describe('http', function () {
3058
})
3159

3260
it('parses the response as ndjson', async function () {
33-
const res = await HTTP.post('http://localhost:3000', {
61+
const res = await HTTP.post(`${process.env.ECHO_SERVER}/echo`, {
3462
body: '{}\n{}'
3563
})
3664

@@ -40,7 +68,8 @@ describe('http', function () {
4068
})
4169

4270
it('parses the response as an async iterable', async function () {
43-
const res = await HTTP.post('http://localhost:3000', {
71+
const res = await HTTP.post('echo', {
72+
base: process.env.ECHO_SERVER,
4473
body: 'hello world'
4574
})
4675

@@ -64,7 +93,7 @@ describe('http', function () {
6493
throw err
6594
}())
6695

67-
const res = await HTTP.post('http://localhost:3000', {
96+
const res = await HTTP.post(process.env.ECHO_SERVER, {
6897
body: toStream.readable(body)
6998
})
7099

@@ -87,7 +116,7 @@ describe('http', function () {
87116
throw err
88117
}())
89118

90-
const res = await HTTP.post('http://localhost:3000', {
119+
const res = await HTTP.post(process.env.ECHO_SERVER, {
91120
body: toStream.readable(body),
92121
signal: controller.signal
93122
})

test/supports.spec.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
'use strict'
22

33
/* eslint-env mocha */
4-
const chai = require('chai')
5-
const dirtyChai = require('dirty-chai')
4+
const { expect } = require('aegir/utils/chai')
65
const supports = require('../src/supports')
76
const env = require('../src/env')
87

9-
chai.use(dirtyChai)
10-
const expect = chai.expect
11-
128
describe('supports', function () {
139
it('supportsFileReader should return false in node', function () {
1410
if (env.isNode) {

test/utils/chai.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)