Skip to content
Open
Show file tree
Hide file tree
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
63 changes: 63 additions & 0 deletions packages/fresh/src/handlers_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { expect } from "@std/expect/expect";
import { isHandlerByMethod, page } from "./handlers.ts";

Deno.test("handlers - page() with no args returns undefined data", () => {
const result = page();
expect(result.data).toBeUndefined();
expect(result.status).toBeUndefined();
expect(result.headers).toBeUndefined();
});

Deno.test("handlers - page() with data returns that data", () => {
const result = page("hello");
expect(result.data).toBe("hello");
});

Deno.test("handlers - page() with null data returns undefined", () => {
// `null ?? undefined` evaluates to `undefined` due to the ?? operator
const result = page(null);
expect(result.data).toBeUndefined();
});

Deno.test("handlers - page() with options returns status and headers", () => {
const result = page({ msg: "hi" }, {
headers: { "X-Custom": "1" },
status: 201,
});
expect(result.data).toEqual({ msg: "hi" });
expect(result.status).toBe(201);
expect(result.headers).toEqual({ "X-Custom": "1" });
});

Deno.test("handlers - page() with partial options", () => {
const result = page({ msg: "hi" }, { status: 404 });
expect(result.data).toEqual({ msg: "hi" });
expect(result.status).toBe(404);
expect(result.headers).toBeUndefined();
});

// -- isHandlerByMethod -------------------------------------------------

Deno.test("handlers - isHandlerByMethod with object returns true", () => {
const handler = { GET: () => new Response("ok") };
expect(isHandlerByMethod(handler)).toBe(true);
});

Deno.test("handlers - isHandlerByMethod with empty object returns true", () => {
// An empty object is still technically an object — the type guard
// distinguishes between functions and method maps.
expect(isHandlerByMethod({})).toBe(true);
});

Deno.test("handlers - isHandlerByMethod with function returns false", () => {
const handler = () => new Response("ok");
expect(isHandlerByMethod(handler)).toBe(false);
});

Deno.test("handlers - isHandlerByMethod with array returns false", () => {
expect(isHandlerByMethod([])).toBe(false);
});

Deno.test("handlers - isHandlerByMethod with null returns false", () => {
expect(isHandlerByMethod(null)).toBe(false);
});
70 changes: 70 additions & 0 deletions packages/fresh/src/otel_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { expect } from "@std/expect/expect";
import type { Span } from "@opentelemetry/api";
import { SpanStatusCode } from "@opentelemetry/api";
import { recordSpanError } from "./otel.ts";

/** Creates a trackable Span mock without external mock libraries. */
function mockSpan() {
const calls: Record<string, unknown[][]> = {};

return {
_calls: calls,
span: {
recordException(err: Error) {
(calls.recordException ??= []).push([err]);
},
setStatus(status: { code: number; message: string }) {
(calls.setStatus ??= []).push([status]);
},
} as Span,
};
}

Deno.test("otel - recordSpanError with Error calls recordException", () => {
const err = new Error("test error");
const { span, _calls } = mockSpan();

recordSpanError(span, err);

expect(_calls.recordException).toBeDefined();
expect(_calls.recordException[0][0]).toBe(err);
expect(_calls.setStatus).toBeUndefined();
});

Deno.test("otel - recordSpanError with string calls setStatus", () => {
const { span, _calls } = mockSpan();

recordSpanError(span, "something broke");

expect(_calls.recordException).toBeUndefined();
expect(_calls.setStatus).toBeDefined();
expect(_calls.setStatus[0][0]).toEqual({
code: SpanStatusCode.ERROR,
message: "something broke",
});
});

Deno.test("otel - recordSpanError with object calls setStatus", () => {
const customErr = { custom: "problem" };
const { span, _calls } = mockSpan();

recordSpanError(span, customErr);

expect(_calls.setStatus).toBeDefined();
expect(_calls.setStatus[0][0]).toEqual({
code: SpanStatusCode.ERROR,
message: String(customErr),
});
});

Deno.test("otel - recordSpanError with number calls setStatus", () => {
const { span, _calls } = mockSpan();

recordSpanError(span, 404);

expect(_calls.setStatus).toBeDefined();
expect(_calls.setStatus[0][0]).toEqual({
code: SpanStatusCode.ERROR,
message: "404",
});
});
26 changes: 26 additions & 0 deletions packages/plugin-vite/src/mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/**
* @module
*
* The official Vite plugin for the
* [Fresh](https://usefresh.dev) web framework for Deno.
*
* This plugin uses Vite's Environment API to provide dual
* client/server builds, HMR, island-based code splitting,
* and Deno-native module resolution for Fresh applications.
*
* @example vite.config.ts
* ```ts
* import { defineConfig } from "vite";
* import { fresh } from "@fresh/plugin-vite";
*
* export default defineConfig({
* plugins: [fresh()],
* });
* ```
*/

import type { Plugin } from "vite";
import {
type FreshViteConfig,
Expand Down Expand Up @@ -27,7 +48,11 @@ import { isBuiltin } from "node:module";
import { load as stdLoadEnv } from "@std/dotenv";
import path from "node:path";

// -- Types ----------------------------------------------------------

/** @category Types */
export type { FreshViteConfig };
/** @category Types */
export type {
ImportCheck,
ImportCheckDiagnostic,
Expand All @@ -41,6 +66,7 @@ export type {
*
* @param config Fresh config options
* @returns Vite plugin with Fresh support
* @category Plugin
*
* @example Basic usage
* ```ts vite.config.ts
Expand Down
Loading