OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / test / unit / api-response.test.js

137 lines · javascript ref:
import test from 'brittle'
import {
  appendVaryHeader,
  getResponseHeader,
  hasResponseHeader,
  writeJson,
  writeText
} from 'p2p-hiverelay/core/relay-node/api-response.js'

function fakeRes (opts = {}) {
  const headers = { ...(opts.headers || {}) }
  const res = {
    headers,
    statusCode: null,
    body: null,
    setHeader (name, value) {
      headers[name] = value
    },
    getHeader (name) {
      const lower = name.toLowerCase()
      const key = Object.keys(headers).find(key => key.toLowerCase() === lower)
      return key ? headers[key] : undefined
    },
    hasHeader (name) {
      const lower = name.toLowerCase()
      return Object.keys(headers).some(key => key.toLowerCase() === lower)
    },
    writeHead (status) {
      this.statusCode = status
    },
    end (body) {
      this.body = body
    }
  }
  if (opts.getHeader === false) delete res.getHeader
  if (opts.hasHeader === false) delete res.hasHeader
  return res
}

test('api response: header helpers are case-insensitive with fallback storage', (t) => {
  const res = fakeRes({ headers: { 'cache-control': 'public, max-age=60' }, getHeader: false, hasHeader: false })
  t.ok(hasResponseHeader(res, 'Cache-Control'))
  t.is(getResponseHeader(res, 'CACHE-CONTROL'), 'public, max-age=60')
  t.absent(hasResponseHeader(res, 'Vary'))
})

test('api response: appendVaryHeader preserves wildcard and avoids duplicates', (t) => {
  const res = fakeRes({ headers: { Vary: 'Accept-Encoding' } })
  appendVaryHeader(res, 'Origin')
  t.is(res.headers.Vary, 'Accept-Encoding, Origin')
  appendVaryHeader(res, 'origin')
  t.is(res.headers.Vary, 'Accept-Encoding, Origin', 'duplicate Vary value is not appended')

  const wildcard = fakeRes({ headers: { Vary: '*' } })
  appendVaryHeader(wildcard, 'Origin')
  t.is(wildcard.headers.Vary, '*', 'wildcard Vary is preserved')
})

test('api response: writeJson applies JSON security defaults', (t) => {
  const res = fakeRes()
  writeJson(res, { ok: true })

  t.is(res.statusCode, 200)
  t.is(res.headers['Content-Type'], 'application/json; charset=utf-8')
  t.is(res.headers['X-Content-Type-Options'], 'nosniff')
  t.is(res.headers['Cache-Control'], 'no-store, max-age=0')
  t.is(res.body, '{"ok":true}\n')
})

test('api response: writeJson preserves explicit cache and extra headers', (t) => {
  const res = fakeRes()
  writeJson(res, { ok: true }, 202, {
    'Cache-Control': 'public, max-age=60',
    'Retry-After': '60'
  })

  t.is(res.statusCode, 202)
  t.is(res.headers['Cache-Control'], 'public, max-age=60')
  t.is(res.headers['Retry-After'], '60')
  t.is(res.headers['X-Content-Type-Options'], 'nosniff')
})

test('api response: writeJson preserves explicit cache on minimal response objects', (t) => {
  const res = fakeMinimalRes()
  writeJson(res, { ok: true }, 200, { 'Cache-Control': 'public, max-age=60' })

  t.is(res.statusCode, 200)
  t.is(res.header('Cache-Control'), 'public, max-age=60')
  t.is(res.header('Content-Type'), 'application/json; charset=utf-8')
  t.is(res.header('X-Content-Type-Options'), 'nosniff')
  t.is(res.body, '{"ok":true}\n')
})

test('api response: writeText applies plain-text security defaults', (t) => {
  const res = fakeRes()
  writeText(res, 'hello\n')

  t.is(res.statusCode, 200)
  t.is(res.headers['Content-Type'], 'text/plain; charset=utf-8')
  t.is(res.headers['X-Content-Type-Options'], 'nosniff')
  t.is(res.headers['Cache-Control'], 'no-store, max-age=0')
  t.is(res.body, 'hello\n')
})

test('api response: writeText preserves explicit cache and status', (t) => {
  const res = fakeMinimalRes()
  writeText(res, 'created\n', 201, { 'Cache-Control': 'public, max-age=10' })

  t.is(res.statusCode, 201)
  t.is(res.header('Content-Type'), 'text/plain; charset=utf-8')
  t.is(res.header('X-Content-Type-Options'), 'nosniff')
  t.is(res.header('Cache-Control'), 'public, max-age=10')
  t.is(res.body, 'created\n')
})

function fakeMinimalRes () {
  const headers = {}
  return {
    statusCode: null,
    body: null,
    setHeader (name, value) {
      headers[name] = value
    },
    header (name) {
      const lower = name.toLowerCase()
      const key = Object.keys(headers).find(key => key.toLowerCase() === lower)
      return key ? headers[key] : undefined
    },
    writeHead (status) {
      this.statusCode = status
    },
    end (body) {
      this.body = body
    }
  }
}