From 8ec50a94661e56726d25b836b2046cc37a1e8230 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Thu, 6 Aug 2026 15:57:50 +0900 Subject: [PATCH 1/9] Verify onNotFound wires to ctx.next() in @fedify/fresh (#863) Assisted-by: Gemini:3.0 --- packages/fresh/src/mod.test.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 packages/fresh/src/mod.test.ts diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts new file mode 100644 index 000000000..48a00b270 --- /dev/null +++ b/packages/fresh/src/mod.test.ts @@ -0,0 +1,30 @@ +import { integrateFetchOptions } from "@fedify/fresh"; +import { assertEquals, assertExists } from "@std/assert"; +import type { Context } from "fresh"; + +function createMockContext( + overrides: Partial> = {}, +): Context { + return { + req: new Request("https://example.com/"), + next: () => Promise.resolve(new Response(null, { status: 404 })), + ...overrides, + } as Context; +} + +Deno.test("integrateFetchOptions() wires onNotFound to ctx.next()", async () => { + let nextCalled = false; + const ctx = createMockContext({ + next: () => { + nextCalled = true; + return Promise.resolve(new Response("fresh page")); + }, + }); + + const options = integrateFetchOptions(ctx); + assertExists(options.onNotFound); + const response = await options.onNotFound(ctx.req); + + assertEquals(nextCalled, true); + assertEquals(await response.text(), "fresh page"); +}); From f285d37318fbac666a46941c27ab6a5ea3f53a8c Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Thu, 6 Aug 2026 15:58:59 +0900 Subject: [PATCH 2/9] Verify onNotAcceptable handles 404 and non-404 in @fedify/fresh (#864) Assisted-by: Gemini:3.0 --- packages/fresh/src/mod.test.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index 48a00b270..15492e501 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -28,3 +28,30 @@ Deno.test("integrateFetchOptions() wires onNotFound to ctx.next()", async () => assertEquals(nextCalled, true); assertEquals(await response.text(), "fresh page"); }); + +Deno.test("onNotAcceptable() returns Fresh response when not 404", async () => { + const ctx = createMockContext({ + next: () => Promise.resolve(new Response("ok", { status: 200 })), + }); + + const options = integrateFetchOptions(ctx); + assertExists(options.onNotAcceptable); + const response = await options.onNotAcceptable(ctx.req); + + assertEquals(response.status, 200); + assertEquals(await response.text(), "ok"); +}); + +Deno.test("onNotAcceptable() returns 406 when Fresh returns 404", async () => { + const ctx = createMockContext({ + next: () => Promise.resolve(new Response(null, { status: 404 })), + }); + + const options = integrateFetchOptions(ctx); + assertExists(options.onNotAcceptable); + const response = await options.onNotAcceptable(ctx.req); + + assertEquals(response.status, 406); + assertEquals(response.headers.get("Vary"), "Accept"); + assertEquals(response.headers.get("Content-Type"), "text/plain"); +}); From 4e0a335be5e4d35a8188d6cf2b43ddc82b81c4b2 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Thu, 6 Aug 2026 16:01:44 +0900 Subject: [PATCH 3/9] Verify integrateHandler passes context data in @fedify/fresh (#865) Assisted-by: Gemini:3.0 --- packages/fresh/src/mod.test.ts | 52 ++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index 15492e501..fcd76ec27 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -1,5 +1,6 @@ -import { integrateFetchOptions } from "@fedify/fresh"; -import { assertEquals, assertExists } from "@std/assert"; +import type { Federation } from "@fedify/fedify"; +import { integrateFetchOptions, integrateHandler } from "@fedify/fresh"; +import { assertEquals, assertExists, assertStrictEquals } from "@std/assert"; import type { Context } from "fresh"; function createMockContext( @@ -55,3 +56,50 @@ Deno.test("onNotAcceptable() returns 406 when Fresh returns 404", async () => { assertEquals(response.headers.get("Vary"), "Accept"); assertEquals(response.headers.get("Content-Type"), "text/plain"); }); + +Deno.test("integrateHandler() calls createContextData and passes result to federation.fetch()", async () => { + const expectedContextData = { userId: "test-user" }; + let receivedContextData: unknown; + let receivedRequest: Request | undefined; + + const mockFederation = { + fetch: (req: Request, opts: { contextData: unknown }) => { + receivedRequest = req; + receivedContextData = opts.contextData; + return Promise.resolve(new Response("ok")); + }, + } as unknown as Federation; + + const ctx = createMockContext(); + const createContextData = (c: Context) => { + assertStrictEquals(c, ctx); + return expectedContextData; + }; + + const handler = integrateHandler(mockFederation, createContextData); + const response = await handler(ctx); + + assertEquals(receivedContextData, expectedContextData); + assertStrictEquals(receivedRequest, ctx.req); + assertEquals(await response.text(), "ok"); +}); + +Deno.test("integrateHandler() supports an async createContextData factory", async () => { + const expectedContextData = { userId: "async-user" }; + let receivedContextData: unknown; + + const mockFederation = { + fetch: (_req: Request, opts: { contextData: unknown }) => { + receivedContextData = opts.contextData; + return Promise.resolve(new Response("ok")); + }, + } as unknown as Federation; + + const createContextData = () => Promise.resolve(expectedContextData); + + const ctx = createMockContext(); + const handler = integrateHandler(mockFederation, createContextData); + await handler(ctx); + + assertEquals(receivedContextData, expectedContextData); +}); From 13668e47fdcff1c82147dc52bd99b142f888dad6 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sat, 8 Aug 2026 20:36:02 +0900 Subject: [PATCH 4/9] Fix onNotFound receiver check in fedify/fresh test --- packages/fresh/src/mod.test.ts | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index fcd76ec27..696d143b8 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -13,21 +13,30 @@ function createMockContext( } as Context; } -Deno.test("integrateFetchOptions() wires onNotFound to ctx.next()", async () => { - let nextCalled = false; - const ctx = createMockContext({ - next: () => { - nextCalled = true; - return Promise.resolve(new Response("fresh page")); +Deno.test("integrateFetchOptions() - onNotFound delegates to ctx.next with correct receiver", async () => { + const notFoundResponse = new Response("Not Found", { status: 404 }); + let passedRequest: Request | undefined; + let capturedThis: unknown; + + // 화살표 함수 대신 일반 function을 사용하여 this 바인딩을 검증 + const mockCtx = { + next(req?: Request) { + capturedThis = this; // 실행 시점의 this(receiver)를 기록 + passedRequest = req; + return Promise.resolve(notFoundResponse); }, - }); + } as unknown as Context; - const options = integrateFetchOptions(ctx); - assertExists(options.onNotFound); - const response = await options.onNotFound(ctx.req); + const options = integrateFetchOptions(mockCtx); + const request = new Request("https://example.com/some-page"); + + const response = await options.onNotFound!(request); - assertEquals(nextCalled, true); - assertEquals(await response.text(), "fresh page"); + // 1. this(receiver)가 mockCtx 자신인지 검증 (this 바인딩 유지 여부) + assertStrictEquals(capturedThis, mockCtx); + // 2. Request 전달 및 응답 검증 + assertEquals(passedRequest, request); + assertEquals(response.status, 404); }); Deno.test("onNotAcceptable() returns Fresh response when not 404", async () => { From 313f8aff0627d7785d06d269e433a8cf7a132a25 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sat, 8 Aug 2026 22:53:55 +0900 Subject: [PATCH 5/9] Use assertStrictEquals for request/response identity in fedify/fresh test --- packages/fresh/src/mod.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index 696d143b8..c94470257 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -35,8 +35,8 @@ Deno.test("integrateFetchOptions() - onNotFound delegates to ctx.next with corre // 1. this(receiver)가 mockCtx 자신인지 검증 (this 바인딩 유지 여부) assertStrictEquals(capturedThis, mockCtx); // 2. Request 전달 및 응답 검증 - assertEquals(passedRequest, request); - assertEquals(response.status, 404); + assertStrictEquals(passedRequest, request); + assertStrictEquals(response, notFoundResponse); }); Deno.test("onNotAcceptable() returns Fresh response when not 404", async () => { From 78522e7a01e26548e7c03dbba2ef41e39cc5a389 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sun, 9 Aug 2026 03:41:15 +0900 Subject: [PATCH 6/9] Remove Korean comments from fedify/fresh test --- packages/fresh/src/mod.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index c94470257..529b107f2 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -18,10 +18,9 @@ Deno.test("integrateFetchOptions() - onNotFound delegates to ctx.next with corre let passedRequest: Request | undefined; let capturedThis: unknown; - // 화살표 함수 대신 일반 function을 사용하여 this 바인딩을 검증 const mockCtx = { next(req?: Request) { - capturedThis = this; // 실행 시점의 this(receiver)를 기록 + capturedThis = this; passedRequest = req; return Promise.resolve(notFoundResponse); }, @@ -32,9 +31,7 @@ Deno.test("integrateFetchOptions() - onNotFound delegates to ctx.next with corre const response = await options.onNotFound!(request); - // 1. this(receiver)가 mockCtx 자신인지 검증 (this 바인딩 유지 여부) assertStrictEquals(capturedThis, mockCtx); - // 2. Request 전달 및 응답 검증 assertStrictEquals(passedRequest, request); assertStrictEquals(response, notFoundResponse); }); From 75437d366bcb66c6a115275b6bcfca817588df98 Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sun, 9 Aug 2026 03:46:57 +0900 Subject: [PATCH 7/9] Add test task to fresh deno.json --- packages/fresh/deno.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/fresh/deno.json b/packages/fresh/deno.json index 4bcce0801..b454cb469 100644 --- a/packages/fresh/deno.json +++ b/packages/fresh/deno.json @@ -19,6 +19,7 @@ ] }, "tasks": { - "check": "deno fmt --check && deno lint && deno check src/*.ts" + "check": "deno fmt --check && deno lint && deno check src/*.ts", + "test": "deno test --allow-all src/mod.test.ts" } } From 685bb362d4545499454ec7ea79b3ee158ffb562a Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sun, 9 Aug 2026 03:58:40 +0900 Subject: [PATCH 8/9] Fix strict equality checks and restore missing test in fedify/fresh test --- packages/fresh/src/mod.test.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index 529b107f2..b3ac37c6f 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -29,7 +29,8 @@ Deno.test("integrateFetchOptions() - onNotFound delegates to ctx.next with corre const options = integrateFetchOptions(mockCtx); const request = new Request("https://example.com/some-page"); - const response = await options.onNotFound!(request); + assertExists(options.onNotFound); + const response = await options.onNotFound(request); assertStrictEquals(capturedThis, mockCtx); assertStrictEquals(passedRequest, request); @@ -45,8 +46,8 @@ Deno.test("onNotAcceptable() returns Fresh response when not 404", async () => { assertExists(options.onNotAcceptable); const response = await options.onNotAcceptable(ctx.req); - assertEquals(response.status, 200); - assertEquals(await response.text(), "ok"); + assertStrictEquals(response.status, 200); + assertStrictEquals(await response.text(), "ok"); }); Deno.test("onNotAcceptable() returns 406 when Fresh returns 404", async () => { @@ -58,9 +59,9 @@ Deno.test("onNotAcceptable() returns 406 when Fresh returns 404", async () => { assertExists(options.onNotAcceptable); const response = await options.onNotAcceptable(ctx.req); - assertEquals(response.status, 406); - assertEquals(response.headers.get("Vary"), "Accept"); - assertEquals(response.headers.get("Content-Type"), "text/plain"); + assertStrictEquals(response.status, 406); + assertStrictEquals(response.headers.get("Vary"), "Accept"); + assertStrictEquals(response.headers.get("Content-Type"), "text/plain"); }); Deno.test("integrateHandler() calls createContextData and passes result to federation.fetch()", async () => { @@ -85,7 +86,7 @@ Deno.test("integrateHandler() calls createContextData and passes result to feder const handler = integrateHandler(mockFederation, createContextData); const response = await handler(ctx); - assertEquals(receivedContextData, expectedContextData); + assertStrictEquals(receivedContextData, expectedContextData); assertStrictEquals(receivedRequest, ctx.req); assertEquals(await response.text(), "ok"); }); @@ -107,5 +108,5 @@ Deno.test("integrateHandler() supports an async createContextData factory", asyn const handler = integrateHandler(mockFederation, createContextData); await handler(ctx); - assertEquals(receivedContextData, expectedContextData); + assertStrictEquals(receivedContextData, expectedContextData); }); From 1232bc7b831cc8bb5f0c7221f3fdac9a654c178b Mon Sep 17 00:00:00 2001 From: OH TAEJUN Date: Sun, 9 Aug 2026 04:59:45 +0900 Subject: [PATCH 9/9] Fix strict equality checks and add missing tests in fedify/fresh --- packages/fresh/src/mod.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fresh/src/mod.test.ts b/packages/fresh/src/mod.test.ts index b3ac37c6f..7f2633096 100644 --- a/packages/fresh/src/mod.test.ts +++ b/packages/fresh/src/mod.test.ts @@ -1,6 +1,6 @@ import type { Federation } from "@fedify/fedify"; import { integrateFetchOptions, integrateHandler } from "@fedify/fresh"; -import { assertEquals, assertExists, assertStrictEquals } from "@std/assert"; +import { assertExists, assertStrictEquals } from "@std/assert"; import type { Context } from "fresh"; function createMockContext( @@ -88,7 +88,7 @@ Deno.test("integrateHandler() calls createContextData and passes result to feder assertStrictEquals(receivedContextData, expectedContextData); assertStrictEquals(receivedRequest, ctx.req); - assertEquals(await response.text(), "ok"); + assertStrictEquals(await response.text(), "ok"); }); Deno.test("integrateHandler() supports an async createContextData factory", async () => {