chore: condense/cleanup bad tests

This commit is contained in:
Aarnav Tale
2026-03-07 15:11:15 -05:00
parent da3132323c
commit 5f2cbebbcd
9 changed files with 200 additions and 855 deletions
-61
View File
@@ -1,61 +0,0 @@
import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
describe("Agent refresh interval", () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
test("setInterval is called with cache_ttl value", () => {
const setIntervalSpy = vi.spyOn(global, "setInterval");
const cache_ttl = 180000; // 3 minutes
// Simulate what the agent does when starting refresh
const refreshInterval = setInterval(() => {
// refresh logic
}, cache_ttl);
expect(setIntervalSpy).toHaveBeenCalledWith(expect.any(Function), cache_ttl);
clearInterval(refreshInterval);
setIntervalSpy.mockRestore();
});
test("interval triggers callback at expected times", () => {
const callback = vi.fn();
const cache_ttl = 60000; // 1 minute for test
const interval = setInterval(callback, cache_ttl);
expect(callback).not.toHaveBeenCalled();
vi.advanceTimersByTime(cache_ttl);
expect(callback).toHaveBeenCalledTimes(1);
vi.advanceTimersByTime(cache_ttl);
expect(callback).toHaveBeenCalledTimes(2);
vi.advanceTimersByTime(cache_ttl);
expect(callback).toHaveBeenCalledTimes(3);
clearInterval(interval);
});
test("clearInterval stops the refresh", () => {
const callback = vi.fn();
const cache_ttl = 60000;
const interval = setInterval(callback, cache_ttl);
vi.advanceTimersByTime(cache_ttl);
expect(callback).toHaveBeenCalledTimes(1);
clearInterval(interval);
vi.advanceTimersByTime(cache_ttl * 5);
expect(callback).toHaveBeenCalledTimes(1); // still 1, not called again
});
});
-82
View File
@@ -1,82 +0,0 @@
import { describe, expect, test } from "vitest";
import { Capabilities, hasCapability, Roles } from "~/server/web/roles";
describe("Self-service pre-auth keys", () => {
describe("Capabilities", () => {
test("generate_own_authkeys capability exists", () => {
expect(Capabilities.generate_own_authkeys).toBeDefined();
expect(typeof Capabilities.generate_own_authkeys).toBe("number");
});
test("generate_own_authkeys is distinct from generate_authkeys", () => {
expect(Capabilities.generate_own_authkeys).not.toBe(Capabilities.generate_authkeys);
});
});
describe("Auditor role", () => {
test("auditor has generate_own_authkeys", () => {
expect(hasCapability("auditor", "generate_own_authkeys")).toBe(true);
});
test("auditor does not have generate_authkeys", () => {
expect(hasCapability("auditor", "generate_authkeys")).toBe(false);
});
test("auditor has read permissions", () => {
expect(hasCapability("auditor", "read_machines")).toBe(true);
expect(hasCapability("auditor", "read_users")).toBe(true);
expect(hasCapability("auditor", "read_policy")).toBe(true);
});
});
describe("Admin roles retain full access", () => {
test("owner has generate_authkeys", () => {
expect(hasCapability("owner", "generate_authkeys")).toBe(true);
});
test("admin has generate_authkeys", () => {
expect(hasCapability("admin", "generate_authkeys")).toBe(true);
});
test("it_admin has generate_authkeys", () => {
expect(hasCapability("it_admin", "generate_authkeys")).toBe(true);
});
test("network_admin has generate_authkeys", () => {
expect(hasCapability("network_admin", "generate_authkeys")).toBe(true);
});
});
describe("Member role", () => {
test("member has no capabilities", () => {
expect(Roles.member).toBe(0);
});
test("member does not have generate_own_authkeys", () => {
expect(hasCapability("member", "generate_own_authkeys")).toBe(false);
});
});
});
describe("providerId subject extraction", () => {
function extractSubject(providerId: string | undefined): string | undefined {
return providerId?.split("/").pop();
}
test("extracts subject from oidc providerId", () => {
expect(extractSubject("oidc/abc123")).toBe("abc123");
});
test("extracts subject from nested providerId", () => {
expect(extractSubject("provider/tenant/user123")).toBe("user123");
});
test("handles single component providerId", () => {
expect(extractSubject("subject")).toBe("subject");
});
test("returns undefined for undefined providerId", () => {
expect(extractSubject(undefined)).toBeUndefined();
});
});
@@ -1,117 +0,0 @@
import { createClient } from "@libsql/client";
import { count, eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/libsql";
import { ulid } from "ulidx";
import { beforeEach, describe, expect, test } from "vitest";
import { users } from "~/server/db/schema";
import { Roles } from "~/server/web/roles";
function createTestDb() {
const client = createClient({ url: ":memory:" });
const db = drizzle(client);
return { client, db };
}
async function setupSchema(client: ReturnType<typeof createClient>) {
await client.execute(`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
sub TEXT NOT NULL UNIQUE,
caps INTEGER NOT NULL DEFAULT 0,
onboarded INTEGER NOT NULL DEFAULT 0
)
`);
}
async function countOwners(db: ReturnType<typeof drizzle>) {
const [result] = await db
.select({ count: count() })
.from(users)
.where(eq(users.caps, Roles.owner));
return result?.count ?? 0;
}
async function simulateOidcLogin(db: ReturnType<typeof drizzle>, subject: string) {
const ownerCount = await countOwners(db);
const needsOwner = ownerCount === 0;
if (needsOwner) {
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles.owner,
})
.onConflictDoUpdate({
target: users.sub,
set: { caps: Roles.owner },
});
} else {
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles.member,
})
.onConflictDoNothing();
}
}
describe("OIDC owner assignment", () => {
let db: ReturnType<typeof drizzle>;
let client: ReturnType<typeof createClient>;
beforeEach(async () => {
const testDb = createTestDb();
db = testDb.db;
client = testDb.client;
await setupSchema(client);
});
test("first user gets owner role", async () => {
await simulateOidcLogin(db, "first-user");
const [user] = await db.select().from(users).where(eq(users.sub, "first-user"));
expect(user.caps).toBe(Roles.owner);
});
test("second user gets member role when owner exists", async () => {
await simulateOidcLogin(db, "first-user");
await simulateOidcLogin(db, "second-user");
const [second] = await db.select().from(users).where(eq(users.sub, "second-user"));
expect(second.caps).toBe(Roles.member);
});
test("existing member becomes owner if no owner exists", async () => {
await db.insert(users).values({
id: ulid(),
sub: "orphaned-user",
caps: Roles.member,
onboarded: false,
});
await simulateOidcLogin(db, "orphaned-user");
const [user] = await db.select().from(users).where(eq(users.sub, "orphaned-user"));
expect(user.caps).toBe(Roles.owner);
});
test("existing member stays member when owner exists", async () => {
await simulateOidcLogin(db, "owner-user");
await db.insert(users).values({
id: ulid(),
sub: "member-user",
caps: Roles.member,
onboarded: false,
});
await simulateOidcLogin(db, "member-user");
const [member] = await db.select().from(users).where(eq(users.sub, "member-user"));
expect(member.caps).toBe(Roles.member);
});
});
+125 -69
View File
@@ -1,81 +1,137 @@
import { dump } from 'js-yaml'; import { dump } from "js-yaml";
import { beforeAll, describe, expect, test } from 'vitest'; import { beforeAll, describe, expect, test } from "vitest";
import { ConfigError } from '~/server/config/error';
import { loadConfig, loadConfigFile } from '~/server/config/load'; import { ConfigError } from "~/server/config/error";
import { clearFakeFiles, createFakeFile } from '../setup/overlay-fs'; import { loadConfig, loadConfigFile } from "~/server/config/load";
import { clearFakeFiles, createFakeFile } from "../setup/overlay-fs";
const writeYaml = (filePath: string, content: unknown) => { const writeYaml = (filePath: string, content: unknown) => {
const yamlContent = dump(content); const yamlContent = dump(content);
createFakeFile(filePath, yamlContent); createFakeFile(filePath, yamlContent);
}; };
describe('Configuration YAML file loading', () => { describe("Configuration YAML file loading", () => {
beforeAll(() => { beforeAll(() => {
clearFakeFiles(); clearFakeFiles();
}); });
test('should correctly parse different types from YAML file', async () => { test("should correctly parse different types from YAML file", async () => {
const filePath = '/config/test-config.yaml'; const filePath = "/config/test-config.yaml";
writeYaml(filePath, { writeYaml(filePath, {
headscale: { headscale: {
url: 'http://localhost:8080', url: "http://localhost:8080",
}, },
oidc: { oidc: {
client_id: 'my-client-id', client_id: "my-client-id",
}, },
server: { server: {
port: 8000, port: 8000,
}, },
integration: { integration: {
agent: { agent: {
enabled: true, enabled: true,
}, },
}, },
}); });
const config = await loadConfigFile(filePath); const config = await loadConfigFile(filePath);
expect(config?.headscale?.url).toBe('http://localhost:8080'); expect(config?.headscale?.url).toBe("http://localhost:8080");
expect(config?.oidc?.client_id).toBe('my-client-id'); expect(config?.oidc?.client_id).toBe("my-client-id");
expect(config?.server?.port).toBe(8000); expect(config?.server?.port).toBe(8000);
expect(config?.integration?.agent?.enabled).toBe(true); expect(config?.integration?.agent?.enabled).toBe(true);
}); });
test('should not throw errors for inaccessible file', async () => { test("should not throw errors for inaccessible file", async () => {
await expect( await expect(loadConfigFile("/non-existent-path/config.yaml")).resolves.toBeUndefined();
loadConfigFile('/non-existent-path/config.yaml'), });
).resolves.toBeUndefined();
});
test('should correctly get a finalized config from YAML', async () => { test("should correctly get a finalized config from YAML", async () => {
const filePath = '/config/minimal-config.yaml'; const filePath = "/config/minimal-config.yaml";
writeYaml(filePath, { writeYaml(filePath, {
headscale: { headscale: {
url: 'http://localhost:8080', url: "http://localhost:8080",
}, },
server: { server: {
cookie_secret: 'thirtytwo-character-cookiesecret', cookie_secret: "thirtytwo-character-cookiesecret",
}, },
}); });
const config = await loadConfig(filePath); const config = await loadConfig(filePath);
expect(config.headscale.url).toBe('http://localhost:8080'); expect(config.headscale.url).toBe("http://localhost:8080");
expect(config.server.cookie_secret).toBe( expect(config.server.cookie_secret).toBe("thirtytwo-character-cookiesecret");
'thirtytwo-character-cookiesecret', });
);
});
test('should throw error for missing required fields', async () => { test("should throw error for missing required fields", async () => {
const filePath = '/config/invalid-config.yaml'; const filePath = "/config/invalid-config.yaml";
writeYaml(filePath, { writeYaml(filePath, {
server: { server: {
port: 8000, port: 8000,
}, },
}); });
await expect(loadConfig(filePath)).rejects.toEqual( await expect(loadConfig(filePath)).rejects.toEqual(
expect.objectContaining( expect.objectContaining(ConfigError.from("INVALID_REQUIRED_FIELDS", { messages: [] })),
ConfigError.from('INVALID_REQUIRED_FIELDS', { messages: [] }), );
), });
);
}); test("oidc.enabled defaults to true when oidc section is present", async () => {
const filePath = "/config/oidc-default-enabled.yaml";
writeYaml(filePath, {
headscale: { url: "http://localhost:8080" },
server: { cookie_secret: "thirtytwo-character-cookiesecret" },
oidc: {
issuer: "https://accounts.google.com",
client_id: "my-client-id",
client_secret: "my-client-secret",
headscale_api_key: "my-api-key",
},
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(true);
});
test("oidc.enabled can be set to false to disable OIDC", async () => {
const filePath = "/config/oidc-disabled.yaml";
writeYaml(filePath, {
headscale: { url: "http://localhost:8080" },
server: { cookie_secret: "thirtytwo-character-cookiesecret" },
oidc: {
enabled: false,
issuer: "https://accounts.google.com",
client_id: "my-client-id",
client_secret: "my-client-secret",
headscale_api_key: "my-api-key",
},
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(false);
});
test("partial oidc config with enabled field can be parsed", async () => {
const filePath = "/config/oidc-partial.yaml";
writeYaml(filePath, {
headscale: { url: "http://localhost:8080" },
server: { cookie_secret: "thirtytwo-character-cookiesecret" },
oidc: { enabled: false },
});
const partialConfig = await loadConfigFile(filePath);
expect(partialConfig?.oidc?.enabled).toBe(false);
});
test("config without oidc section has undefined oidc", async () => {
const filePath = "/config/no-oidc.yaml";
writeYaml(filePath, {
headscale: { url: "http://localhost:8080" },
server: { cookie_secret: "thirtytwo-character-cookiesecret" },
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeUndefined();
});
}); });
+74 -43
View File
@@ -1,54 +1,85 @@
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from "vitest";
import { ConfigError } from '~/server/config/error';
import { loadConfig, loadConfigEnv } from '~/server/config/load'; import { ConfigError } from "~/server/config/error";
import { loadConfig, loadConfigEnv } from "~/server/config/load";
const envVarSnapshot = { ...process.env }; const envVarSnapshot = { ...process.env };
describe('Configuration environment variable handling', () => { describe("Configuration environment variable handling", () => {
beforeEach(() => { beforeEach(() => {
process.env = { ...envVarSnapshot }; process.env = { ...envVarSnapshot };
}); });
test('should correctly parse different types from env vars', async () => { test("should correctly parse different types from env vars", async () => {
process.env.HEADPLANE_HEADSCALE__URL = 'http://localhost:8080'; process.env.HEADPLANE_HEADSCALE__URL = "http://localhost:8080";
process.env.HEADPLANE_OIDC__CLIENT_ID = 'my-client-id'; process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
process.env.HEADPLANE_SERVER__PORT = '8000'; process.env.HEADPLANE_SERVER__PORT = "8000";
process.env.HEADPLANE_INTEGRATION__AGENT__ENABLED = 'true'; process.env.HEADPLANE_INTEGRATION__AGENT__ENABLED = "true";
const config = await loadConfigEnv(); const config = await loadConfigEnv();
expect(config?.headscale?.url).toBe('http://localhost:8080'); expect(config?.headscale?.url).toBe("http://localhost:8080");
expect(config?.oidc?.client_id).toBe('my-client-id'); expect(config?.oidc?.client_id).toBe("my-client-id");
expect(config?.server?.port).toBe(8000); expect(config?.server?.port).toBe(8000);
expect(config?.integration?.agent?.enabled).toBe(true); expect(config?.integration?.agent?.enabled).toBe(true);
}); });
test('should not load env vars without the HEADPLANE_ prefix', async () => { test("should not load env vars without the HEADPLANE_ prefix", async () => {
process.env.HEADPLANE_HEADSCALE__URL = 'http://localhost:8080'; process.env.HEADPLANE_HEADSCALE__URL = "http://localhost:8080";
process.env.OTHER_PREFIX_OIDC__CLIENT_ID = 'should-not-be-loaded'; process.env.OTHER_PREFIX_OIDC__CLIENT_ID = "should-not-be-loaded";
const config = await loadConfigEnv(); const config = await loadConfigEnv();
expect(config?.headscale?.url).toBe('http://localhost:8080'); expect(config?.headscale?.url).toBe("http://localhost:8080");
expect(config?.oidc?.client_id).toBeUndefined(); expect(config?.oidc?.client_id).toBeUndefined();
}); });
test('should correctly get a finalized config from env vars', async () => { test("should correctly get a finalized config from env vars", async () => {
process.env.HEADPLANE_HEADSCALE__URL = 'http://localhost:8080'; process.env.HEADPLANE_HEADSCALE__URL = "http://localhost:8080";
process.env.HEADPLANE_SERVER__COOKIE_SECRET = process.env.HEADPLANE_SERVER__COOKIE_SECRET = "thirtytwo-character-cookiesecret";
'thirtytwo-character-cookiesecret';
const config = await loadConfig('./non-existent-path.yaml'); const config = await loadConfig("./non-existent-path.yaml");
expect(config.headscale.url).toBe('http://localhost:8080'); expect(config.headscale.url).toBe("http://localhost:8080");
expect(config.server.cookie_secret).toBe( expect(config.server.cookie_secret).toBe("thirtytwo-character-cookiesecret");
'thirtytwo-character-cookiesecret', });
);
});
test('should throw error for missing required fields', async () => { test("should throw error for missing required fields", async () => {
process.env.HEADPLANE_SERVER__PORT = '8000'; process.env.HEADPLANE_SERVER__PORT = "8000";
await expect(loadConfig('./non-existent-path.yaml')).rejects.toEqual( await expect(loadConfig("./non-existent-path.yaml")).rejects.toEqual(
expect.objectContaining( expect.objectContaining(ConfigError.from("INVALID_REQUIRED_FIELDS", { messages: [] })),
ConfigError.from('INVALID_REQUIRED_FIELDS', { messages: [] }), );
), });
);
}); test("oidc.enabled can be set via HEADPLANE_OIDC__ENABLED env var", async () => {
process.env.HEADPLANE_OIDC__ENABLED = "true";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
const config = await loadConfigEnv();
expect(config?.oidc?.enabled).toBe(true);
expect(config?.oidc?.issuer).toBe("https://accounts.google.com");
});
test("oidc.enabled=false can be set via env var", async () => {
process.env.HEADPLANE_OIDC__ENABLED = "false";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
const config = await loadConfigEnv();
expect(config?.oidc?.enabled).toBe(false);
});
test("oidc.enabled=false via env var preserves full OIDC config", async () => {
process.env.HEADPLANE_HEADSCALE__URL = "http://localhost:8080";
process.env.HEADPLANE_SERVER__COOKIE_SECRET = "thirtytwo-character-cookiesecret";
process.env.HEADPLANE_OIDC__ENABLED = "false";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
process.env.HEADPLANE_OIDC__CLIENT_SECRET = "my-client-secret";
process.env.HEADPLANE_OIDC__HEADSCALE_API_KEY = "my-api-key";
const config = await loadConfig("./non-existent-path.yaml");
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(false);
expect(config.oidc?.issuer).toBe("https://accounts.google.com");
expect(config.oidc?.client_id).toBe("my-client-id");
});
}); });
-165
View File
@@ -1,165 +0,0 @@
import { dump } from "js-yaml";
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
import { loadConfig, loadConfigEnv, loadConfigFile } from "~/server/config/load";
import { clearFakeFiles, createFakeFile } from "../setup/overlay-fs";
const writeYaml = (filePath: string, content: unknown) => {
const yamlContent = dump(content);
createFakeFile(filePath, yamlContent);
};
const baseConfig = {
headscale: {
url: "http://localhost:8080",
},
server: {
cookie_secret: "thirtytwo-character-cookiesecret",
},
};
const fullOidcConfig = {
enabled: true,
issuer: "https://accounts.google.com",
client_id: "my-client-id",
client_secret: "my-client-secret",
headscale_api_key: "my-api-key",
};
describe("OIDC enabled configuration", () => {
beforeAll(() => {
clearFakeFiles();
});
test("oidc.enabled defaults to true when oidc section is present", async () => {
const filePath = "/config/oidc-default-enabled.yaml";
writeYaml(filePath, {
...baseConfig,
oidc: {
issuer: "https://accounts.google.com",
client_id: "my-client-id",
client_secret: "my-client-secret",
headscale_api_key: "my-api-key",
},
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(true);
});
test("oidc.enabled can be explicitly set to true", async () => {
const filePath = "/config/oidc-explicit-true.yaml";
writeYaml(filePath, {
...baseConfig,
oidc: fullOidcConfig,
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(true);
});
test("oidc.enabled can be set to false to disable OIDC", async () => {
const filePath = "/config/oidc-disabled.yaml";
writeYaml(filePath, {
...baseConfig,
oidc: {
...fullOidcConfig,
enabled: false,
},
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(false);
});
test("oidc section can be defined with enabled: false for templating purposes", async () => {
const filePath = "/config/oidc-templating.yaml";
writeYaml(filePath, {
...baseConfig,
oidc: {
enabled: false,
issuer: "https://example.com",
client_id: "placeholder-client-id",
client_secret: "placeholder-client-secret",
headscale_api_key: "placeholder-api-key",
},
});
const config = await loadConfig(filePath);
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(false);
expect(config.oidc?.issuer).toBe("https://example.com");
expect(config.oidc?.client_id).toBe("placeholder-client-id");
});
test("partial oidc config with enabled field can be parsed", async () => {
const filePath = "/config/oidc-partial.yaml";
writeYaml(filePath, {
...baseConfig,
oidc: {
enabled: false,
},
});
// This should parse without error at the partial config level
const partialConfig = await loadConfigFile(filePath);
expect(partialConfig?.oidc?.enabled).toBe(false);
});
test("config without oidc section has undefined oidc", async () => {
const filePath = "/config/no-oidc.yaml";
writeYaml(filePath, baseConfig);
const config = await loadConfig(filePath);
expect(config.oidc).toBeUndefined();
});
});
// Environment variable tests for oidc.enabled
const envVarSnapshot = { ...process.env };
describe("OIDC enabled via environment variables", () => {
beforeEach(() => {
process.env = { ...envVarSnapshot };
});
test("oidc.enabled can be set via HEADPLANE_OIDC__ENABLED env var", async () => {
process.env.HEADPLANE_OIDC__ENABLED = "true";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
const config = await loadConfigEnv();
expect(config?.oidc?.enabled).toBe(true);
expect(config?.oidc?.issuer).toBe("https://accounts.google.com");
});
test("oidc.enabled=false can be set via env var", async () => {
process.env.HEADPLANE_OIDC__ENABLED = "false";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
const config = await loadConfigEnv();
expect(config?.oidc?.enabled).toBe(false);
expect(config?.oidc?.issuer).toBe("https://accounts.google.com");
});
test("oidc.enabled can be set via env var to disable full OIDC config", async () => {
process.env.HEADPLANE_HEADSCALE__URL = "http://localhost:8080";
process.env.HEADPLANE_SERVER__COOKIE_SECRET = "thirtytwo-character-cookiesecret";
process.env.HEADPLANE_OIDC__ENABLED = "false";
process.env.HEADPLANE_OIDC__ISSUER = "https://accounts.google.com";
process.env.HEADPLANE_OIDC__CLIENT_ID = "my-client-id";
process.env.HEADPLANE_OIDC__CLIENT_SECRET = "my-client-secret";
process.env.HEADPLANE_OIDC__HEADSCALE_API_KEY = "my-api-key";
const config = await loadConfig("./non-existent-path.yaml");
expect(config.oidc).toBeDefined();
expect(config.oidc?.enabled).toBe(false);
// All other OIDC fields should still be present
expect(config.oidc?.issuer).toBe("https://accounts.google.com");
expect(config.oidc?.client_id).toBe("my-client-id");
});
});
-94
View File
@@ -1,94 +0,0 @@
import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
vi.mock("react-router", () => ({
useRevalidator: vi.fn(),
}));
vi.mock("usehooks-ts", () => ({
useInterval: vi.fn(),
}));
vi.mock("react", async () => {
const actual = await vi.importActual("react");
return {
...actual,
createContext: vi.fn(() => ({ Provider: vi.fn() })),
useContext: vi.fn(),
useEffect: vi.fn(),
useState: vi.fn(),
};
});
describe("LiveDataProvider", () => {
beforeEach(() => vi.useFakeTimers());
afterEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
});
describe("refresh interval", () => {
test("uses 3 second interval", async () => {
const { useInterval } = await import("usehooks-ts");
expect(useInterval).toBeDefined();
expect(3000).toBe(3000);
});
test("disables interval when paused", () => {
const visible = true;
const paused = true;
const interval = visible && !paused ? 3000 : null;
expect(interval).toBeNull();
});
test("disables interval when hidden", () => {
const visible = false;
const paused = false;
const interval = visible && !paused ? 3000 : null;
expect(interval).toBeNull();
});
test("only revalidates when idle", () => {
const mockRevalidate = vi.fn();
const revalidateIfIdle = (state: string) => {
if (state === "idle") mockRevalidate();
};
revalidateIfIdle("idle");
expect(mockRevalidate).toHaveBeenCalledTimes(1);
mockRevalidate.mockClear();
revalidateIfIdle("loading");
expect(mockRevalidate).not.toHaveBeenCalled();
});
});
describe("useLiveData hook", () => {
test("returns pause and resume functions", () => {
const mockSetPaused = vi.fn();
const hook = {
pause: () => mockSetPaused(true),
resume: () => mockSetPaused(false),
};
hook.pause();
expect(mockSetPaused).toHaveBeenCalledWith(true);
hook.resume();
expect(mockSetPaused).toHaveBeenCalledWith(false);
});
});
});
describe("pending approval page", () => {
test("redirects when user has access", () => {
const hasAccess = true;
const redirect = hasAccess ? "/machines" : null;
expect(redirect).toBe("/machines");
});
test("stays on page when user lacks access", () => {
const hasAccess = false;
const redirect = hasAccess ? "/machines" : null;
expect(redirect).toBeNull();
});
});
-180
View File
@@ -1,180 +0,0 @@
import { createClient } from "@libsql/client";
import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/libsql";
import { ulid } from "ulidx";
import { beforeEach, describe, expect, test } from "vitest";
import { users } from "~/server/db/schema";
import { Roles } from "~/server/web/roles";
// Create in-memory database for testing
function createTestDb() {
const client = createClient({ url: ":memory:" });
const db = drizzle(client);
return { client, db };
}
// Create the users table schema
async function setupSchema(client: ReturnType<typeof createClient>) {
await client.execute(`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
sub TEXT NOT NULL UNIQUE,
caps INTEGER NOT NULL DEFAULT 0,
onboarded INTEGER NOT NULL DEFAULT 0
)
`);
}
describe("Session role assignment", () => {
let db: ReturnType<typeof drizzle>;
let client: ReturnType<typeof createClient>;
beforeEach(async () => {
const testDb = createTestDb();
db = testDb.db;
client = testDb.client;
await setupSchema(client);
});
describe("reassignSubject upsert behavior", () => {
test("creates user record when subject does not exist", async () => {
const subject = "new-user-subject";
const role = "admin";
// Verify user doesn't exist
const beforeInsert = await db.select().from(users).where(eq(users.sub, subject));
expect(beforeInsert.length).toBe(0);
// Perform upsert (simulating reassignSubject)
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles[role],
onboarded: false,
})
.onConflictDoUpdate({
target: users.sub,
set: { caps: Roles[role] },
});
// Verify user was created with correct role
const afterInsert = await db.select().from(users).where(eq(users.sub, subject));
expect(afterInsert.length).toBe(1);
expect(afterInsert[0].caps).toBe(Roles.admin);
});
test("updates existing user role without creating duplicate", async () => {
const subject = "existing-user";
const initialRole = "member";
const newRole = "admin";
// Create initial user
await db.insert(users).values({
id: ulid(),
sub: subject,
caps: Roles[initialRole],
onboarded: true,
});
// Verify initial state
const beforeUpdate = await db.select().from(users).where(eq(users.sub, subject));
expect(beforeUpdate.length).toBe(1);
expect(beforeUpdate[0].caps).toBe(Roles.member);
expect(beforeUpdate[0].onboarded).toBe(true);
// Perform upsert (simulating reassignSubject)
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles[newRole],
onboarded: false,
})
.onConflictDoUpdate({
target: users.sub,
set: { caps: Roles[newRole] },
});
// Verify role was updated, no duplicate created
const afterUpdate = await db.select().from(users).where(eq(users.sub, subject));
expect(afterUpdate.length).toBe(1);
expect(afterUpdate[0].caps).toBe(Roles.admin);
// onboarded should remain true (not overwritten)
expect(afterUpdate[0].onboarded).toBe(true);
});
test("can assign all role types", async () => {
const roles = ["admin", "network_admin", "it_admin", "auditor", "member"] as const;
for (const role of roles) {
const subject = `user-${role}`;
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles[role],
onboarded: false,
})
.onConflictDoUpdate({
target: users.sub,
set: { caps: Roles[role] },
});
const [user] = await db.select().from(users).where(eq(users.sub, subject));
expect(user.caps).toBe(Roles[role]);
}
});
});
describe("member role handling", () => {
test("member role has zero capabilities", async () => {
const subject = "member-user";
await db.insert(users).values({
id: ulid(),
sub: subject,
caps: Roles.member,
onboarded: false,
});
const [user] = await db.select().from(users).where(eq(users.sub, subject));
expect(user.caps).toBe(0);
});
test("upgrading from member to admin grants ui_access", async () => {
const subject = "upgrading-user";
// Start as member
await db.insert(users).values({
id: ulid(),
sub: subject,
caps: Roles.member,
onboarded: false,
});
// Upgrade to admin
await db
.insert(users)
.values({
id: ulid(),
sub: subject,
caps: Roles.admin,
onboarded: false,
})
.onConflictDoUpdate({
target: users.sub,
set: { caps: Roles.admin },
});
const [user] = await db.select().from(users).where(eq(users.sub, subject));
expect(user.caps).toBe(Roles.admin);
expect(user.caps).not.toBe(0);
});
});
});
+1 -44
View File
@@ -1,8 +1,7 @@
import { describe, expect, test } from "vitest"; import { describe, expect, test } from "vitest";
import type { User } from "~/types/User"; import type { User } from "~/types/User";
import { getUserDisplayName } from "~/utils/user";
import { filterUsersWithValidIds, getUserDisplayName } from "~/utils/user";
const makeUser = (overrides: Partial<User>): User => ({ const makeUser = (overrides: Partial<User>): User => ({
id: "default-id", id: "default-id",
@@ -11,48 +10,6 @@ const makeUser = (overrides: Partial<User>): User => ({
...overrides, ...overrides,
}); });
describe("filterUsersWithValidIds", () => {
test("keeps users with valid ID and name", () => {
const users = [makeUser({ id: "123", name: "John" })];
const result = filterUsersWithValidIds(users);
expect(result).toHaveLength(1);
expect(result[0].id).toBe("123");
});
test("keeps users with valid ID but no name", () => {
const users = [makeUser({ id: "123", name: "" })];
const result = filterUsersWithValidIds(users);
expect(result).toHaveLength(1);
});
test("keeps users with valid ID and no optional fields", () => {
const users = [makeUser({ id: "123", name: "", displayName: undefined, email: undefined })];
const result = filterUsersWithValidIds(users);
expect(result).toHaveLength(1);
});
test("removes users with empty ID", () => {
const users = [makeUser({ id: "", name: "John" })];
const result = filterUsersWithValidIds(users);
expect(result).toHaveLength(0);
});
test("handles mix of valid and invalid", () => {
const users = [
makeUser({ id: "123", name: "John" }),
makeUser({ id: "", name: "Jane" }),
makeUser({ id: "456", name: "" }),
];
const result = filterUsersWithValidIds(users);
expect(result).toHaveLength(2);
expect(result.map((u) => u.id)).toEqual(["123", "456"]);
});
test("returns empty for empty input", () => {
expect(filterUsersWithValidIds([])).toHaveLength(0);
});
});
describe("getUserDisplayName", () => { describe("getUserDisplayName", () => {
test("uses name when set", () => { test("uses name when set", () => {
const user = makeUser({ id: "123", name: "John" }); const user = makeUser({ id: "123", name: "John" });