* feat(typescript-client): add Deno compatibility
- Switch build from tsc to tsup for dual CJS + ESM output with proper exports field
- Add deno_setup.ts preload that injects Jest-compatible globals (describe/test/expect) via @std/testing/bdd and @std/expect
- Fix generated client.gen.ts: exclude hey-api internal `client` field from RequestInit spread to avoid conflict with Deno.HttpClient
- Add test:deno npm script using --unstable-sloppy-imports and --preload
- Add test-typescript-client-deno CI job using denoland/setup-deno@v2 (v2.x)
- Update docs: rename page to TypeScript / JavaScript Client, add Deno installation section
* feat: add Deno compatibility to ai-sdk and chat integrations
- Switch ai-sdk and chat builds from tsc to tsup (ESM bundle, eliminates
extension-less import issues in Deno)
- Add deno.json import map to ai-sdk redirecting 'vitest' to a custom
vitest-compat.ts shim and bare npm specifiers to npm: URLs
- Add vitest-compat.ts shim implementing vi.fn()/vi.spyOn()/vi.mocked()
using @std/expect's Symbol.for("@MOCK") interface so toHaveBeenCalledWith
and other mock matchers work under Deno
- Add test:deno script to ai-sdk (all 30 tests pass under Deno)
* ci: add Deno test job for ai-sdk integration
Adds a new test-ai-sdk-integration-deno CI job that runs the ai-sdk
unit tests under Deno LTS, verifying Deno compatibility of the package.
* fix: remove broken link to non-existent n8n blog post in streamlit post
* fix: patch client.gen.ts for Deno compatibility during generation
Add a post-generation patch step to generate-clients.sh that removes
the hey-api internal 'client' field from the RequestInit spread in
client.gen.ts. Deno's Request constructor rejects 'client' because it
conflicts with the Deno.HttpClient option name.
82 lines
3 KiB
TypeScript
82 lines
3 KiB
TypeScript
/**
|
|
* Vitest compatibility shim for running tests under Deno.
|
|
*
|
|
* Redirected from 'vitest' via deno.json import map.
|
|
* Implements vi.fn() / vi.spyOn() / vi.mocked() using the @std/expect
|
|
* MockCall interface so that @std/expect matchers (toHaveBeenCalledWith, etc.) work.
|
|
*/
|
|
|
|
import { beforeAll, beforeEach, afterAll, afterEach, describe, it } from "jsr:@std/testing/bdd";
|
|
import { expect } from "jsr:@std/expect";
|
|
|
|
// @std/expect recognises mock functions via this well-known symbol (@std/expect 1.0.18+)
|
|
const MOCK_SYMBOL = Symbol.for("@MOCK");
|
|
|
|
type MockCall = {
|
|
args: unknown[];
|
|
returned?: unknown;
|
|
thrown?: unknown;
|
|
timestamp: number;
|
|
returns: boolean;
|
|
throws: boolean;
|
|
};
|
|
|
|
function createMock(impl?: (...args: unknown[]) => unknown) {
|
|
let currentImpl = impl;
|
|
const calls: MockCall[] = [];
|
|
const mockInfo = { calls };
|
|
|
|
const mockFn = function (this: unknown, ...args: unknown[]) {
|
|
const call: MockCall = {
|
|
args,
|
|
timestamp: Date.now(),
|
|
returns: false,
|
|
throws: false,
|
|
};
|
|
calls.push(call);
|
|
try {
|
|
const result = currentImpl ? currentImpl.apply(this, args) : undefined;
|
|
call.returned = result;
|
|
call.returns = true;
|
|
return result;
|
|
} catch (err) {
|
|
call.thrown = err;
|
|
call.throws = true;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
// @std/expect mock interface — required for toHaveBeenCalledWith etc.
|
|
(mockFn as any)[MOCK_SYMBOL] = mockInfo;
|
|
|
|
// vitest-style chainable methods
|
|
(mockFn as any).mockReturnValue = (val: unknown) => { currentImpl = () => val; return mockFn; };
|
|
(mockFn as any).mockResolvedValue = (val: unknown) => { currentImpl = () => Promise.resolve(val); return mockFn; };
|
|
(mockFn as any).mockRejectedValue = (val: unknown) => { currentImpl = () => Promise.reject(val); return mockFn; };
|
|
(mockFn as any).mockImplementation = (fn: (...args: unknown[]) => unknown) => { currentImpl = fn; return mockFn; };
|
|
(mockFn as any).mockReset = () => { calls.length = 0; currentImpl = undefined; return mockFn; };
|
|
(mockFn as any).mockClear = () => { calls.length = 0; return mockFn; };
|
|
(mockFn as any).mockRestore = () => {};
|
|
|
|
return mockFn;
|
|
}
|
|
|
|
export const vi = {
|
|
fn: (impl?: (...args: unknown[]) => unknown) => createMock(impl),
|
|
|
|
// vi.mocked() is a TypeScript type cast — just return the same value at runtime
|
|
mocked: <T>(fn: T): T => fn,
|
|
|
|
spyOn: <T extends Record<string, unknown>>(obj: T, method: keyof T) => {
|
|
const original = obj[method];
|
|
const mock = createMock(typeof original === "function" ? (original as (...args: unknown[]) => unknown) : undefined);
|
|
const restore = () => {
|
|
obj[method] = original;
|
|
};
|
|
(mock as any).mockRestore = restore;
|
|
obj[method] = mock as unknown as T[keyof T];
|
|
return mock;
|
|
},
|
|
};
|
|
|
|
export { describe, it, it as test, beforeAll, beforeEach, afterAll, afterEach, expect };
|