Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion src/stringify-cookie.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { stringifyCookie } from "./index.js";
import { stringifyCookie, parseCookie } from "./index.js";

describe("cookie.stringifyCookie", () => {
it("should stringify object", () => {
Expand All @@ -14,15 +14,123 @@ describe("cookie.stringifyCookie", () => {
expect(stringifyCookie({ a: "1", b: undefined })).toEqual("a=1");
});

it("should return empty string for empty object", () => {
expect(stringifyCookie({})).toEqual("");
});

it("should return empty string when all values are undefined", () => {
expect(stringifyCookie({ a: undefined, b: undefined })).toEqual("");
});

it("should stringify empty string values", () => {
expect(stringifyCookie({ a: "" })).toEqual("a=");
expect(stringifyCookie({ a: "", b: "" })).toEqual("a=; b=");
});

it("should URL-encode values by default", () => {
expect(stringifyCookie({ foo: "bar baz" })).toEqual("foo=bar%20baz");
expect(stringifyCookie({ foo: "a=b" })).toEqual("foo=a%3Db");
expect(stringifyCookie({ foo: "hello;world" })).toEqual(
"foo=hello%3Bworld",
);
});

it("should error on invalid keys", () => {
expect(() => stringifyCookie({ "test=": "" })).toThrow(
/cookie name is invalid/,
);
});

it.each([["foo bar"], ["foo;bar"], ["foo\tbar"], ["foo\nbar"]])(
"should throw for invalid name: %s",
(name) => {
expect(() => stringifyCookie({ [name]: "val" })).toThrow(
/cookie name is invalid/,
);
},
);

it("should error on invalid values", () => {
expect(() => stringifyCookie({ test: ";" }, { encode: (x) => x })).toThrow(
/cookie val is invalid/,
);
});

it.each([
["foo!bar"],
["foo#bar"],
["foo$bar"],
["foo&bar"],
["foo*bar"],
["foo+bar"],
["foo-bar"],
["foo.bar"],
["foo^bar"],
["foo_bar"],
["foo`bar"],
["foo|bar"],
["foo~bar"],
["foo7bar"],
])("should accept valid cookie name: %s", (name) => {
expect(stringifyCookie({ [name]: "val" })).toEqual(`${name}=val`);
});

describe('with "encode" option', () => {
it("should use custom encode function", () => {
expect(
stringifyCookie(
{ foo: "bar" },
{
encode: (v) => Buffer.from(v, "utf8").toString("base64"),
},
),
).toEqual("foo=YmFy");
});

it("should pass through values with identity encoder", () => {
expect(stringifyCookie({ foo: "bar" }, { encode: (x) => x })).toEqual(
"foo=bar",
);
});

it("should throw when custom encoder produces invalid value", () => {
expect(() =>
stringifyCookie({ foo: "bar" }, { encode: () => "invalid value" }),
).toThrow(/cookie val is invalid/);
});
});

describe("roundtrip with parseCookie", () => {
it("should roundtrip simple values", () => {
const cookies = { foo: "bar", baz: "qux" };
const str = stringifyCookie(cookies);
expect(parseCookie(str)).toEqual(cookies);
});

it("should roundtrip URL-encoded values", () => {
const cookies = { session: "abc 123", token: "x=y&z" };
const str = stringifyCookie(cookies);
expect(parseCookie(str)).toEqual(cookies);
});

it("should roundtrip empty values", () => {
const cookies = { a: "", b: "value" };
const str = stringifyCookie(cookies);
expect(parseCookie(str)).toEqual(cookies);
});

it("should roundtrip single cookie", () => {
const cookies = { session_id: "abc123def456" };
const str = stringifyCookie(cookies);
expect(parseCookie(str)).toEqual(cookies);
});

it("should roundtrip with custom encode/decode", () => {
const encode = (v: string) => Buffer.from(v, "utf8").toString("base64");
const decode = (v: string) => Buffer.from(v, "base64").toString("utf8");
const cookies = { data: "hello world" };
const str = stringifyCookie(cookies, { encode });
expect(parseCookie(str, { decode })).toEqual(cookies);
});
});
});
Loading