mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-02-13 20:55:42 +01:00
- Fix syntax errors in skills markdown files (.github/skills, .opencode/skills) - Change typescript to tsx for code blocks with JSX - Replace ellipsis (...) in array examples with valid syntax - Separate CSS from TypeScript into distinct code blocks - Convert JavaScript object examples to valid JSON in docs - Fix enum definitions with proper comma separation
257 lines
6.6 KiB
TypeScript
257 lines
6.6 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
|
|
// Mock neonAuth from lib/auth/server
|
|
const mockNeonAuth = vi.fn();
|
|
vi.mock("../../lib/auth/server", () => ({
|
|
neonAuth: () => mockNeonAuth(),
|
|
getAuthenticatedPlatformUser: () => mockNeonAuth(),
|
|
hasPlatformAccess: vi.fn(() => true),
|
|
isPlatformRole: vi.fn((role: string) =>
|
|
["PLATFORM_SUPER_ADMIN", "PLATFORM_ADMIN", "PLATFORM_SUPPORT"].includes(
|
|
role
|
|
)
|
|
),
|
|
}));
|
|
|
|
// Mock database
|
|
const mockDb = {
|
|
company: {
|
|
findMany: vi.fn(),
|
|
count: vi.fn(),
|
|
create: vi.fn(),
|
|
findUnique: vi.fn(),
|
|
update: vi.fn(),
|
|
},
|
|
user: {
|
|
count: vi.fn(),
|
|
create: vi.fn(),
|
|
},
|
|
session: {
|
|
count: vi.fn(),
|
|
},
|
|
};
|
|
|
|
vi.mock("../../lib/db", () => ({
|
|
db: mockDb,
|
|
}));
|
|
|
|
// Mock bcryptjs
|
|
vi.mock("bcryptjs", () => ({
|
|
hash: vi.fn(() => "hashed_password"),
|
|
}));
|
|
|
|
describe("Platform API Endpoints", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("Authentication Requirements", () => {
|
|
it("should require platform authentication", async () => {
|
|
mockNeonAuth.mockResolvedValue({ user: null });
|
|
|
|
// Test that endpoints check for authentication
|
|
const endpoints = [
|
|
"/api/platform/companies",
|
|
"/api/platform/companies/123",
|
|
];
|
|
|
|
endpoints.forEach((endpoint) => {
|
|
expect(endpoint).toMatch(/^\/api\/platform\//);
|
|
});
|
|
});
|
|
|
|
it("should require platform user role", () => {
|
|
const regularUser = {
|
|
id: "1",
|
|
email: "regular@user.com",
|
|
role: "USER",
|
|
companyId: "company-123",
|
|
};
|
|
|
|
const platformUser = {
|
|
id: "2",
|
|
email: "admin@notso.ai",
|
|
role: "PLATFORM_SUPER_ADMIN",
|
|
companyId: null,
|
|
};
|
|
|
|
const isPlatformRole = (role: string) =>
|
|
["PLATFORM_SUPER_ADMIN", "PLATFORM_ADMIN", "PLATFORM_SUPPORT"].includes(
|
|
role
|
|
);
|
|
|
|
expect(isPlatformRole(regularUser.role)).toBe(false);
|
|
expect(isPlatformRole(platformUser.role)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("Company Management", () => {
|
|
it("should return companies list structure", async () => {
|
|
const mockCompanies = [
|
|
{
|
|
id: "1",
|
|
name: "Company A",
|
|
status: "ACTIVE",
|
|
createdAt: new Date(),
|
|
_count: { users: 5 },
|
|
},
|
|
{
|
|
id: "2",
|
|
name: "Company B",
|
|
status: "SUSPENDED",
|
|
createdAt: new Date(),
|
|
_count: { users: 3 },
|
|
},
|
|
];
|
|
|
|
mockDb.company.findMany.mockResolvedValue(mockCompanies);
|
|
mockDb.company.count.mockResolvedValue(2);
|
|
mockDb.user.count.mockResolvedValue(8);
|
|
mockDb.session.count.mockResolvedValue(150);
|
|
|
|
const result = await mockDb.company.findMany({
|
|
include: {
|
|
_count: {
|
|
select: { users: true },
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
|
|
expect(result).toHaveLength(2);
|
|
expect(result[0]).toHaveProperty("name");
|
|
expect(result[0]).toHaveProperty("status");
|
|
expect(result[0]._count).toHaveProperty("users");
|
|
});
|
|
|
|
it("should create company with admin user placeholder", async () => {
|
|
const newCompany = {
|
|
id: "123",
|
|
name: "New Company",
|
|
status: "ACTIVE",
|
|
maxUsers: 10,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
const newUser = {
|
|
id: "456",
|
|
email: "admin@newcompany.com",
|
|
name: "Admin User",
|
|
role: "ADMIN",
|
|
companyId: "123",
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
invitedBy: "platform@notso.ai",
|
|
invitedAt: new Date(),
|
|
};
|
|
|
|
mockDb.company.create.mockResolvedValue({
|
|
...newCompany,
|
|
users: [newUser],
|
|
});
|
|
|
|
const result = await mockDb.company.create({
|
|
data: {
|
|
name: "New Company",
|
|
users: {
|
|
create: {
|
|
email: "admin@newcompany.com",
|
|
name: "Admin User",
|
|
role: "ADMIN",
|
|
invitedBy: "platform@notso.ai",
|
|
invitedAt: new Date(),
|
|
},
|
|
},
|
|
},
|
|
include: { users: true },
|
|
});
|
|
|
|
expect(result.name).toBe("New Company");
|
|
expect(result.users).toHaveLength(1);
|
|
expect(result.users[0].email).toBe("admin@newcompany.com");
|
|
expect(result.users[0].role).toBe("ADMIN");
|
|
});
|
|
|
|
it("should update company status", async () => {
|
|
const updatedCompany = {
|
|
id: "123",
|
|
name: "Test Company",
|
|
status: "SUSPENDED",
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
mockDb.company.update.mockResolvedValue(updatedCompany);
|
|
|
|
const result = await mockDb.company.update({
|
|
where: { id: "123" },
|
|
data: { status: "SUSPENDED" },
|
|
});
|
|
|
|
expect(result.status).toBe("SUSPENDED");
|
|
});
|
|
});
|
|
|
|
describe("Role-Based Access Control", () => {
|
|
it("should enforce role permissions", () => {
|
|
const permissions = {
|
|
SUPER_ADMIN: {
|
|
canCreateCompany: true,
|
|
canUpdateCompany: true,
|
|
canDeleteCompany: true,
|
|
canViewAllData: true,
|
|
},
|
|
ADMIN: {
|
|
canCreateCompany: false,
|
|
canUpdateCompany: false,
|
|
canDeleteCompany: false,
|
|
canViewAllData: true,
|
|
},
|
|
SUPPORT: {
|
|
canCreateCompany: false,
|
|
canUpdateCompany: false,
|
|
canDeleteCompany: false,
|
|
canViewAllData: true,
|
|
},
|
|
};
|
|
|
|
Object.entries(permissions).forEach(([role, perms]) => {
|
|
if (role === "SUPER_ADMIN") {
|
|
expect(perms.canCreateCompany).toBe(true);
|
|
expect(perms.canUpdateCompany).toBe(true);
|
|
} else {
|
|
expect(perms.canCreateCompany).toBe(false);
|
|
expect(perms.canUpdateCompany).toBe(false);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Error Handling", () => {
|
|
it("should handle missing required fields", () => {
|
|
const invalidPayloads = [
|
|
{ name: "Company" }, // Missing admin fields
|
|
{ adminEmail: "admin@test.com" }, // Missing company name
|
|
{ name: "", adminEmail: "admin@test.com" }, // Empty name
|
|
];
|
|
|
|
invalidPayloads.forEach((payload) => {
|
|
const isValid = payload.name && payload.adminEmail;
|
|
expect(isValid).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockDb.company.findUnique.mockRejectedValue(new Error("Database error"));
|
|
|
|
try {
|
|
await mockDb.company.findUnique({ where: { id: "123" } });
|
|
} catch (error) {
|
|
expect(error).toBeInstanceOf(Error);
|
|
expect((error as Error).message).toBe("Database error");
|
|
}
|
|
});
|
|
});
|
|
});
|