f4995d987d
Fixes incorrect vi.mock paths that were causing tests to fail. The mock path should match the import path in the route files. This addresses the authProvider test mock path issue on PR #2. Co-Authored-By: Paperclip <noreply@paperclip.ing>
153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
|
// Mutable state to control mock behavior per test
|
|
let dbSelectResult: unknown[] = [];
|
|
const mockEq = vi.fn((_col: unknown, _val: unknown) => ({ col: _col, val: _val }));
|
|
const mockDecryptSecret = vi.fn((s: string) => `decrypted:${s}`);
|
|
|
|
vi.mock("../db", () => {
|
|
const authProviderConfig = new Proxy(
|
|
{ _name: "auth_provider_config" },
|
|
{
|
|
get(target, prop) {
|
|
if (prop === "_name") return "auth_provider_config";
|
|
if (prop === "$inferSelect") return {};
|
|
return { table: "auth_provider_config", column: prop };
|
|
},
|
|
}
|
|
);
|
|
|
|
return {
|
|
getDb: () => ({
|
|
select: () => ({
|
|
from: () => ({
|
|
where: () => ({
|
|
limit: () => dbSelectResult,
|
|
[Symbol.iterator]: function* () {
|
|
for (const item of dbSelectResult) yield item;
|
|
},
|
|
0: dbSelectResult[0],
|
|
length: dbSelectResult.length,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
authProviderConfig,
|
|
eq: mockEq,
|
|
decryptSecret: mockDecryptSecret,
|
|
};
|
|
});
|
|
|
|
async function reimportAuth() {
|
|
vi.resetModules();
|
|
vi.doMock("./db", () => ({
|
|
getDb: () => ({
|
|
select: () => ({
|
|
from: () => ({
|
|
where: () => ({
|
|
limit: () => dbSelectResult,
|
|
[Symbol.iterator]: function* () {
|
|
for (const item of dbSelectResult) yield item;
|
|
},
|
|
0: dbSelectResult[0],
|
|
length: dbSelectResult.length,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
authProviderConfig: {},
|
|
eq: mockEq,
|
|
decryptSecret: mockDecryptSecret,
|
|
}));
|
|
const mod = await import("../lib/auth.js");
|
|
return mod;
|
|
}
|
|
|
|
describe("auth init", () => {
|
|
const originalEnv = { ...process.env };
|
|
|
|
beforeEach(() => {
|
|
dbSelectResult = [];
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = { ...originalEnv };
|
|
});
|
|
|
|
it("falls back to env vars when DB returns empty", async () => {
|
|
process.env = {
|
|
...originalEnv,
|
|
OIDC_ISSUER: "https://issuer.example.com",
|
|
OIDC_CLIENT_ID: "test-client-id",
|
|
OIDC_CLIENT_SECRET: "test-client-secret",
|
|
BETTER_AUTH_SECRET: "test-secret",
|
|
BETTER_AUTH_URL: "http://localhost:3000",
|
|
NODE_ENV: "test",
|
|
};
|
|
|
|
const { initAuth, getAuth } = await reimportAuth();
|
|
await initAuth();
|
|
expect(getAuth()).toBeDefined();
|
|
});
|
|
|
|
it("uses DB config and decrypts clientSecret when DB has enabled provider", async () => {
|
|
const dbConfig = {
|
|
id: "config-id",
|
|
providerId: "okta",
|
|
displayName: "Okta",
|
|
issuerUrl: "https://okta.example.com",
|
|
internalBaseUrl: null,
|
|
clientId: "okta-client-id",
|
|
clientSecret: "encrypted:okta-secret",
|
|
scopes: "openid profile email",
|
|
enabled: true,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
dbSelectResult = [dbConfig];
|
|
|
|
process.env = {
|
|
...originalEnv,
|
|
BETTER_AUTH_SECRET: "test-secret",
|
|
BETTER_AUTH_URL: "http://localhost:3000",
|
|
NODE_ENV: "test",
|
|
};
|
|
|
|
const { initAuth, getAuth } = await reimportAuth();
|
|
await initAuth();
|
|
expect(getAuth()).toBeDefined();
|
|
expect(mockDecryptSecret).toHaveBeenCalledWith("encrypted:okta-secret");
|
|
});
|
|
|
|
it("throws when BETTER_AUTH_SECRET is missing and AUTH_DISABLED is not set", async () => {
|
|
process.env = {
|
|
...originalEnv,
|
|
OIDC_ISSUER: "",
|
|
OIDC_CLIENT_ID: "",
|
|
OIDC_CLIENT_SECRET: "",
|
|
NODE_ENV: "test",
|
|
};
|
|
delete process.env.BETTER_AUTH_SECRET;
|
|
delete process.env.AUTH_DISABLED;
|
|
|
|
const { initAuth } = await reimportAuth();
|
|
await expect(initAuth()).rejects.toThrow(
|
|
"[FATAL] BETTER_AUTH_SECRET environment variable is required when auth is enabled"
|
|
);
|
|
});
|
|
|
|
it("builds placeholder auth when AUTH_DISABLED=true without throwing", async () => {
|
|
process.env = {
|
|
...originalEnv,
|
|
AUTH_DISABLED: "true",
|
|
NODE_ENV: "test",
|
|
};
|
|
delete process.env.BETTER_AUTH_SECRET;
|
|
|
|
const { initAuth, getAuth } = await reimportAuth();
|
|
await expect(initAuth()).resolves.toBeUndefined();
|
|
expect(getAuth()).toBeDefined();
|
|
});
|
|
});
|