Skip to content

Commit 7c4270a

Browse files
committed
refactor: simplify mocking & adjust tests for API changes
1 parent ffb39c9 commit 7c4270a

File tree

5 files changed

+39
-44
lines changed

5 files changed

+39
-44
lines changed

tests/doublecsrf.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { DoubleCsrfConfig } from "@/types"
33
/* eslint-disable @typescript-eslint/ban-ts-comment */
44
import { assert, describe, it } from "vitest"
55
import { createTestSuite } from "./testsuite"
6-
import { HEADER_KEY } from "./utils/constants"
6+
import { COOKIE_SECRET, HEADER_KEY } from "./utils/constants";
77
import {
88
attachResponseValuesToRequest,
99
getMultipleSecrets,
@@ -17,7 +17,7 @@ createTestSuite("csrf-csrf unsigned, single secret", {
1717
getSessionIdentifier: legacySessionIdentifier,
1818
})
1919
createTestSuite("csrf-csrf signed, single secret", {
20-
cookieOptions: { signed: true },
20+
cookieOptions: { signed: true, getSigningSecret: () => COOKIE_SECRET },
2121
getSecret: getSingleSecret,
2222
getSessionIdentifier: legacySessionIdentifier,
2323
errorConfig: {
@@ -29,7 +29,7 @@ createTestSuite("csrf-csrf signed, single secret", {
2929
createTestSuite("csrf-csrf signed with custom options, single secret", {
3030
getSecret: getSingleSecret,
3131
getSessionIdentifier: legacySessionIdentifier,
32-
cookieOptions: { name: "__Host.test-the-thing.token", signed: true, sameSite: "strict" },
32+
cookieOptions: { name: "__Host.test-the-thing.token", signed: true, getSigningSecret: () => COOKIE_SECRET, sameSite: "strict" },
3333
size: 128,
3434
delimiter: "~",
3535
hmacAlgorithm: "sha512",
@@ -40,7 +40,7 @@ createTestSuite("csrf-csrf unsigned, multiple secrets", {
4040
getSessionIdentifier: legacySessionIdentifier,
4141
})
4242
createTestSuite("csrf-csrf signed, multiple secrets", {
43-
cookieOptions: { signed: true },
43+
cookieOptions: { signed: true, getSigningSecret: () => COOKIE_SECRET },
4444
getSecret: getMultipleSecrets,
4545
getSessionIdentifier: legacySessionIdentifier,
4646
delimiter: "~",
@@ -49,7 +49,7 @@ createTestSuite("csrf-csrf signed, multiple secrets", {
4949
createTestSuite("csrf-csrf signed with custom options, multiple secrets", {
5050
getSecret: getMultipleSecrets,
5151
getSessionIdentifier: legacySessionIdentifier,
52-
cookieOptions: { name: "__Host.test-the-thing.token", signed: true, sameSite: "strict" },
52+
cookieOptions: { name: "__Host.test-the-thing.token", signed: true, getSigningSecret: () => COOKIE_SECRET, sameSite: "strict" },
5353
size: 128,
5454
errorConfig: {
5555
statusCode: 401,

tests/testsuite.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { doubleCsrf } from "@/index"
2-
import type { DoubleCsrfConfig } from "@/types"
3-
import type { Request, Response } from "@tinyhttp/app"
4-
import { serialize as serializeCookie } from "@tinyhttp/cookie"
5-
import { sign } from "@tinyhttp/cookie-signature"
1+
import { serialize as serializeCookie } from "@otterhttp/cookie"
2+
import { sign } from "@otterhttp/cookie-signature"
63
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
74
import { assert, describe, expect, it } from "vitest"
85

9-
import { HEADER_KEY, TEST_TOKEN } from "./utils/constants"
6+
import { COOKIE_SECRET, HEADER_KEY, TEST_TOKEN } from "./utils/constants";
107
import { getCookieFromRequest, getCookieFromResponse, switchSecret } from "./utils/helpers"
118
import { generateMocks, generateMocksWithToken, next } from "./utils/mock"
9+
import type { Request, Response } from "./utils/mock-types"
10+
11+
import { doubleCsrf } from "@/index"
12+
import type { DoubleCsrfConfig } from "@/types"
1213

1314
type CreateTestSuite = (
1415
name: string,
@@ -63,7 +64,7 @@ export const createTestSuite: CreateTestSuite = (name, doubleCsrfOptions) => {
6364
it("should attach both a token and its hash to the response and return a token", () => {
6465
const { mockRequest, decodedCookieValue, setCookie } = generateMocksWithTokenInternal()
6566
const cookieValue = signed
66-
? `s:${sign(decodedCookieValue as string, mockRequest.secret as string)}`
67+
? `s:${sign(decodedCookieValue as string, COOKIE_SECRET)}`
6768
: decodedCookieValue
6869

6970
const expectedSetCookieValue = serializeCookie(cookieName, cookieValue as string, {
@@ -109,7 +110,7 @@ export const createTestSuite: CreateTestSuite = (name, doubleCsrfOptions) => {
109110
// modify the cookie to make the token/hash pair invalid
110111
const cookieJar = signed ? mockRequest.signedCookies : mockRequest.cookies
111112
cookieJar[cookieName] = signed
112-
? `s:${sign(`${(decodedCookieValue as string).split("|")[0]}|invalid-hash`, mockRequest.secret as string)}`
113+
? `s:${sign(`${(decodedCookieValue as string).split("|")[0]}|invalid-hash`, COOKIE_SECRET)}`
113114
: `${(decodedCookieValue as string).split("|")[0]}|invalid-hash`
114115

115116
expect(() =>
@@ -120,7 +121,7 @@ export const createTestSuite: CreateTestSuite = (name, doubleCsrfOptions) => {
120121
).to.throw(invalidCsrfTokenError.message)
121122

122123
// just an invalid value in the cookie
123-
cookieJar[cookieName] = signed ? `s:${sign("invalid-value", mockRequest.secret as string)}` : "invalid-value"
124+
cookieJar[cookieName] = signed ? `s:${sign("invalid-value", COOKIE_SECRET)}` : "invalid-value"
124125

125126
expect(() =>
126127
generateToken(mockRequest, mockResponse, {
@@ -146,7 +147,7 @@ export const createTestSuite: CreateTestSuite = (name, doubleCsrfOptions) => {
146147
// modify the cookie to make the token/hash pair invalid
147148
const cookieJar = signed ? mockRequest.signedCookies : mockRequest.cookies
148149
cookieJar[cookieName] = signed
149-
? `s:${sign(`${(decodedCookieValue as string).split("|")[0]}|invalid-hash`, mockRequest.secret as string)}`
150+
? `s:${sign(`${(decodedCookieValue as string).split("|")[0]}|invalid-hash`, COOKIE_SECRET)}`
150151
: `${(decodedCookieValue as string).split("|")[0]}|invalid-hash`
151152

152153
assert.doesNotThrow(() => {
@@ -160,7 +161,7 @@ export const createTestSuite: CreateTestSuite = (name, doubleCsrfOptions) => {
160161
assert.notEqual(generatedToken, csrfToken)
161162

162163
// just an invalid value in the cookie
163-
cookieJar[cookieName] = signed ? `s:${sign("invalid-value", mockRequest.secret as string)}` : "invalid-value"
164+
cookieJar[cookieName] = signed ? `s:${sign("invalid-value", COOKIE_SECRET)}` : "invalid-value"
164165

165166
assert.doesNotThrow(() => {
166167
generatedToken = generateToken(mockRequest, mockResponse, {

tests/utils/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Request, Response } from "@tinyhttp/app"
1+
import type { Request, Response } from "./mock-types.js"
22

33
const SECRET_1 = "secrets must be unique and must not"
44
const SECRET_2 = "be used elsewhere, nor be sentences"

tests/utils/mock-types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { IncomingMessage, ServerResponse } from "node:http"
2+
3+
export type Request = IncomingMessage & {
4+
cookies: Record<string, unknown>
5+
signedCookies: Record<string, unknown>
6+
}
7+
8+
export type Response = ServerResponse

tests/utils/mock.ts

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,26 @@
1-
import type { CsrfRequestValidator, CsrfTokenCreator } from "@/types.js"
2-
import type { Request, Response } from "@tinyhttp/app"
3-
import { parse } from "@tinyhttp/cookie"
1+
import { IncomingMessage, ServerResponse } from "node:http"
2+
import { parse } from "@otterhttp/cookie"
43
import { cookieParser, signedCookie } from "@tinyhttp/cookie-parser"
5-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
64
import { assert } from "vitest"
5+
76
import { COOKIE_SECRET, HEADER_KEY } from "./constants.js"
87
import { getCookieFromRequest, getCookieValueFromResponse } from "./helpers.js"
8+
import type { Request, Response } from "./mock-types"
9+
10+
import type { CsrfRequestValidator, CsrfTokenCreator } from "@/types.js"
911

1012
// Create some request and response mocks
1113
export const generateMocks = () => {
12-
const mockRequest = {
13-
headers: {
14-
cookie: "",
15-
},
14+
const mockRequest: Request = Object.assign(new IncomingMessage(undefined as any), {
1615
cookies: {},
1716
signedCookies: {},
18-
secret: COOKIE_SECRET,
19-
} satisfies Partial<Request> as Request
20-
21-
// Internally mock the headers as a map.
22-
const mockResponseHeaders = new Map<string, string | string[]>()
23-
mockResponseHeaders.set("set-cookie", [] as string[])
17+
})
2418

25-
// Mock bare minimum properties for testing.
26-
const mockResponse = {
27-
getHeader: (name: string) => mockResponseHeaders.get(name),
28-
setHeader: (name: string, value: string) => {
29-
mockResponseHeaders.set(name, value)
30-
return mockResponse
31-
},
32-
} satisfies Partial<Response> as Response
19+
const mockResponse: Response = new ServerResponse(mockRequest)
3320

3421
return {
3522
mockRequest,
3623
mockResponse,
37-
mockResponseHeaders,
3824
}
3925
}
4026

@@ -57,16 +43,17 @@ export const generateMocksWithToken = ({
5743
generateToken,
5844
validateRequest,
5945
}: GenerateMocksWithTokenOptions) => {
60-
const { mockRequest, mockResponse, mockResponseHeaders } = generateMocks()
46+
const { mockRequest, mockResponse } = generateMocks()
6147

6248
const csrfToken = generateToken(mockRequest, mockResponse)
6349
const { setCookie, cookieValue } = getCookieValueFromResponse(mockResponse)
6450
mockRequest.headers.cookie = `${cookieName}=${cookieValue};`
6551
const decodedCookieValue = signed
66-
? signedCookie(parse(mockRequest.headers.cookie)[cookieName], mockRequest.secret as string)
52+
? signedCookie(parse(mockRequest.headers.cookie)[cookieName], COOKIE_SECRET)
6753
: // signedCookie already decodes the value, but we need it if it's not signed.
6854
decodeURIComponent(cookieValue)
69-
// Have to delete the cookies object otherwise cookieParser will skip it's parsing.
55+
// Have to delete the cookies object otherwise cookieParser will skip its parsing.
56+
// @ts-expect-error
7057
mockRequest.cookies = undefined
7158
cookieParserMiddleware(mockRequest, mockResponse, next)
7259
assert.equal(getCookieFromRequest(cookieName, signed, mockRequest), decodedCookieValue)
@@ -81,7 +68,6 @@ export const generateMocksWithToken = ({
8168
decodedCookieValue,
8269
mockRequest,
8370
mockResponse,
84-
mockResponseHeaders,
8571
setCookie,
8672
}
8773
}

0 commit comments

Comments
 (0)