From 34bd4f54b21cad6e3405489a186afe64487ca3a7 Mon Sep 17 00:00:00 2001 From: Timothy Foster Date: Thu, 24 Feb 2022 11:05:31 -0600 Subject: [PATCH] Unit Tests for Netlify Adapter split_headers function (#4108) * Extract split_headers to its own file so it can be unit tested * Unit tests for split_headers * no need for a custom suite Co-authored-by: Rich Harris --- packages/adapter-netlify/package.json | 4 +- packages/adapter-netlify/src/handler.js | 31 +---------- packages/adapter-netlify/src/headers.js | 29 +++++++++++ packages/adapter-netlify/src/headers.spec.js | 54 ++++++++++++++++++++ pnpm-lock.yaml | 2 + 5 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 packages/adapter-netlify/src/headers.js create mode 100644 packages/adapter-netlify/src/headers.spec.js diff --git a/packages/adapter-netlify/package.json b/packages/adapter-netlify/package.json index 3540ce1ec28e..87fd9ef5b46b 100644 --- a/packages/adapter-netlify/package.json +++ b/packages/adapter-netlify/package.json @@ -24,6 +24,7 @@ "scripts": { "dev": "rimraf files && rollup -cw", "build": "rimraf files && rollup -c", + "test": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\"", "lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format", "format": "npm run check-format -- --write", "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore", @@ -41,6 +42,7 @@ "@rollup/plugin-node-resolve": "^13.0.5", "@sveltejs/kit": "workspace:*", "rimraf": "^3.0.2", - "rollup": "^2.58.0" + "rollup": "^2.58.0", + "uvu": "^0.5.2" } } diff --git a/packages/adapter-netlify/src/handler.js b/packages/adapter-netlify/src/handler.js index a81c53978d54..13eb9175c680 100644 --- a/packages/adapter-netlify/src/handler.js +++ b/packages/adapter-netlify/src/handler.js @@ -1,5 +1,6 @@ import './shims'; import { Server } from '0SERVER'; +import { split_headers } from './headers'; /** * @param {import('@sveltejs/kit').SSRManifest} manifest @@ -55,33 +56,3 @@ function to_request(event) { return new Request(rawUrl, init); } - -/** - * Splits headers into two categories: single value and multi value - * @param {Headers} headers - * @returns {{ - * headers: Record, - * multiValueHeaders: Record - * }} - */ -function split_headers(headers) { - /** @type {Record} */ - const h = {}; - - /** @type {Record} */ - const m = {}; - - headers.forEach((value, key) => { - if (key === 'set-cookie') { - // @ts-expect-error (headers.raw() is non-standard) - m[key] = headers.raw()[key]; - } else { - h[key] = value; - } - }); - - return { - headers: h, - multiValueHeaders: m - }; -} diff --git a/packages/adapter-netlify/src/headers.js b/packages/adapter-netlify/src/headers.js new file mode 100644 index 000000000000..b317e854c27b --- /dev/null +++ b/packages/adapter-netlify/src/headers.js @@ -0,0 +1,29 @@ +/** + * Splits headers into two categories: single value and multi value + * @param {Headers} headers + * @returns {{ + * headers: Record, + * multiValueHeaders: Record + * }} + */ +export function split_headers(headers) { + /** @type {Record} */ + const h = {}; + + /** @type {Record} */ + const m = {}; + + headers.forEach((value, key) => { + if (key === 'set-cookie') { + // @ts-expect-error (headers.raw() is non-standard) + m[key] = headers.raw()[key]; + } else { + h[key] = value; + } + }); + + return { + headers: h, + multiValueHeaders: m + }; +} diff --git a/packages/adapter-netlify/src/headers.spec.js b/packages/adapter-netlify/src/headers.spec.js new file mode 100644 index 000000000000..3086cbb1e87f --- /dev/null +++ b/packages/adapter-netlify/src/headers.spec.js @@ -0,0 +1,54 @@ +import '../src/shims.js'; +import { test } from 'uvu'; +import * as assert from 'uvu/assert'; +import { split_headers } from '../src/headers.js'; + +test('empty headers', () => { + const headers = new Headers(); + + const result = split_headers(headers); + + assert.equal(result, { + headers: {}, + multiValueHeaders: {} + }); +}); + +test('single-value headers', () => { + const headers = new Headers(); + headers.append('Location', '/apple'); + headers.append('Content-Type', 'application/json'); + + const result = split_headers(headers); + + assert.equal(result, { + headers: { + // Note: becomes lowercase even if specified as uppercase + location: '/apple', + 'content-type': 'application/json' + }, + multiValueHeaders: {} + }); +}); + +test('multi-value headers', () => { + // https://httpwg.org/specs/rfc7231.html#http.date + const wednesday = 'Wed, 23 Feb 2022 21:01:48 GMT'; + const thursday = 'Thu, 24 Feb 2022 21:01:48 GMT'; + + const headers = new Headers(); + headers.append('Set-Cookie', `flavor=sugar; Expires=${wednesday}`); + headers.append('Set-Cookie', `diameter=6cm; Expires=${thursday}`); + + const result = split_headers(headers); + + // it splits at actual cookie boundaries, not the commas in the dates + assert.equal(result, { + headers: {}, + multiValueHeaders: { + 'set-cookie': [`flavor=sugar; Expires=${wednesday}`, `diameter=6cm; Expires=${thursday}`] + } + }); +}); + +test.run(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 185609670d25..362c9d04d594 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -98,6 +98,7 @@ importers: rimraf: ^3.0.2 rollup: ^2.58.0 tiny-glob: ^0.2.9 + uvu: ^0.5.2 dependencies: '@iarna/toml': 2.2.5 esbuild: 0.14.21 @@ -110,6 +111,7 @@ importers: '@sveltejs/kit': link:../kit rimraf: 3.0.2 rollup: 2.60.2 + uvu: 0.5.2 packages/adapter-node: specifiers: