fix: remove nested .git folders, re-add as normal directories
This commit is contained in:
@@ -0,0 +1,526 @@
|
||||
/**
|
||||
* Global test setup — mock heavy external dependencies so unit tests
|
||||
* never touch real databases, APIs, or file-system keys.
|
||||
*/
|
||||
|
||||
import { mock } from "bun:test";
|
||||
import crypto from "crypto";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Generate a real RSA key pair for modules that call crypto.createPrivateKey()
|
||||
// at import time (e.g. readSecureValue.ts).
|
||||
// ---------------------------------------------------------------------------
|
||||
const { privateKey: _testPrivateKey, publicKey: _testPublicKey } =
|
||||
crypto.generateKeyPairSync("rsa", {
|
||||
modulusLength: 2048,
|
||||
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
||||
publicKeyEncoding: { type: "spki", format: "pem" },
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock the globalEvents module — many source files import `events` from here.
|
||||
// We provide both `events` and `setupEventDebugger` so that no test
|
||||
// encounters "export not found" when another test's mock.module is stale.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
mock.module("../src/modules/globalEvents", () => ({
|
||||
events: {
|
||||
emit: mock(),
|
||||
on: mock(),
|
||||
off: mock(),
|
||||
once: mock(),
|
||||
removeAllListeners: mock(),
|
||||
},
|
||||
setupEventDebugger: mock(),
|
||||
}));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock modules that are commonly mocked by test files at top-level.
|
||||
// Having them in the preload ensures that even when per-test mock.module
|
||||
// calls persist globally, the baseline mock is complete.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
mock.module("../src/modules/fetchMicrosoftUser", () => ({
|
||||
fetchMicrosoftUser: mock(() => Promise.resolve({})),
|
||||
}));
|
||||
|
||||
mock.module("../src/managers/sessions", () => ({
|
||||
sessions: {
|
||||
create: mock(() =>
|
||||
Promise.resolve({
|
||||
accessToken: "mock-access",
|
||||
refreshToken: "mock-refresh",
|
||||
}),
|
||||
),
|
||||
fetch: mock(() => Promise.resolve(null)),
|
||||
},
|
||||
}));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock the constants module — almost every source file imports from here.
|
||||
// We provide safe defaults so modules can be imported without side-effects.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
mock.module("../src/constants", () => ({
|
||||
prisma: createMockPrisma(),
|
||||
PORT: "3333",
|
||||
API_BASE_URL: "http://localhost:3333",
|
||||
sessionDuration: 30 * 24 * 60 * 60_000,
|
||||
accessTokenDuration: "10min",
|
||||
refreshTokenDuration: "30d",
|
||||
accessTokenPrivateKey: _testPrivateKey,
|
||||
refreshTokenPrivateKey: _testPrivateKey,
|
||||
permissionsPrivateKey: _testPrivateKey,
|
||||
secureValuesPrivateKey: _testPrivateKey,
|
||||
secureValuesPublicKey: _testPublicKey,
|
||||
msalClient: { acquireTokenByCode: mock(() => Promise.resolve({})) },
|
||||
connectWiseApi: {
|
||||
get: mock(() => Promise.resolve({ data: {} })),
|
||||
post: mock(() => Promise.resolve({ data: {} })),
|
||||
put: mock(() => Promise.resolve({ data: {} })),
|
||||
patch: mock(() => Promise.resolve({ data: {} })),
|
||||
delete: mock(() => Promise.resolve({ data: {} })),
|
||||
},
|
||||
redis: {
|
||||
get: mock(() => Promise.resolve(null)),
|
||||
set: mock(() => Promise.resolve("OK")),
|
||||
del: mock(() => Promise.resolve(1)),
|
||||
},
|
||||
unifi: createMockUnifi(),
|
||||
unifiControllerBaseUrl: "https://unifi.test.local",
|
||||
unifiSite: "default",
|
||||
unifiUsername: "admin",
|
||||
unifiPassword: "test-pass",
|
||||
io: { of: mock(() => ({ on: mock() })) },
|
||||
engine: {},
|
||||
}));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Build a complete mock constants object for use with `mock.module()`.
|
||||
*
|
||||
* Pass `overrides` to replace specific exports (e.g. a custom prisma mock).
|
||||
* All keys from the preload mock are included so that downstream modules
|
||||
* importing named exports (secureValuesPublicKey, connectWiseApi, etc.)
|
||||
* never encounter "export not found" errors.
|
||||
*/
|
||||
export function buildMockConstants(
|
||||
overrides: Record<string, any> = {},
|
||||
): Record<string, any> {
|
||||
return {
|
||||
prisma: createMockPrisma(),
|
||||
PORT: "3333",
|
||||
API_BASE_URL: "http://localhost:3333",
|
||||
sessionDuration: 30 * 24 * 60 * 60_000,
|
||||
accessTokenDuration: "10min",
|
||||
refreshTokenDuration: "30d",
|
||||
accessTokenPrivateKey: _testPrivateKey,
|
||||
refreshTokenPrivateKey: _testPrivateKey,
|
||||
permissionsPrivateKey: _testPrivateKey,
|
||||
secureValuesPrivateKey: _testPrivateKey,
|
||||
secureValuesPublicKey: _testPublicKey,
|
||||
msalClient: { acquireTokenByCode: mock(() => Promise.resolve({})) },
|
||||
connectWiseApi: {
|
||||
get: mock(() => Promise.resolve({ data: {} })),
|
||||
post: mock(() => Promise.resolve({ data: {} })),
|
||||
put: mock(() => Promise.resolve({ data: {} })),
|
||||
patch: mock(() => Promise.resolve({ data: {} })),
|
||||
delete: mock(() => Promise.resolve({ data: {} })),
|
||||
},
|
||||
redis: {
|
||||
get: mock(() => Promise.resolve(null)),
|
||||
set: mock(() => Promise.resolve("OK")),
|
||||
del: mock(() => Promise.resolve(1)),
|
||||
},
|
||||
unifi: createMockUnifi(),
|
||||
unifiControllerBaseUrl: "https://unifi.test.local",
|
||||
unifiSite: "default",
|
||||
unifiUsername: "admin",
|
||||
unifiPassword: "test-pass",
|
||||
io: { of: mock(() => ({ on: mock() })) },
|
||||
engine: {},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a complete mock globalEvents object for use with `mock.module()`.
|
||||
* Includes both `events` and `setupEventDebugger` so downstream modules
|
||||
* never encounter "export not found" errors.
|
||||
*/
|
||||
export function buildMockGlobalEvents(
|
||||
overrides: Record<string, any> = {},
|
||||
): Record<string, any> {
|
||||
return {
|
||||
events: {
|
||||
emit: mock(),
|
||||
on: mock(),
|
||||
off: mock(),
|
||||
once: mock(),
|
||||
removeAllListeners: mock(),
|
||||
},
|
||||
setupEventDebugger: mock(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createMockPrisma() {
|
||||
const createModelProxy = () =>
|
||||
new Proxy(
|
||||
{},
|
||||
{
|
||||
get(_target, prop) {
|
||||
return mock(() => Promise.resolve(null));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(_target, prop) {
|
||||
if (prop === "$connect" || prop === "$disconnect")
|
||||
return mock(() => Promise.resolve());
|
||||
return createModelProxy();
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function createMockUnifi() {
|
||||
return {
|
||||
login: mock(() => Promise.resolve()),
|
||||
getAllSites: mock(() => Promise.resolve([])),
|
||||
getSiteOverview: mock(() => Promise.resolve({})),
|
||||
getDevices: mock(() => Promise.resolve([])),
|
||||
getWlanConf: mock(() => Promise.resolve([])),
|
||||
updateWlanConf: mock(() => Promise.resolve({})),
|
||||
getNetworks: mock(() => Promise.resolve([])),
|
||||
createSite: mock(() =>
|
||||
Promise.resolve({ name: "default", description: "Default" }),
|
||||
),
|
||||
getWlanGroups: mock(() => Promise.resolve([])),
|
||||
createWlanGroup: mock(() => Promise.resolve({})),
|
||||
getUserGroups: mock(() => Promise.resolve([])),
|
||||
createUserGroup: mock(() => Promise.resolve({})),
|
||||
getApGroups: mock(() => Promise.resolve([])),
|
||||
createApGroup: mock(() => Promise.resolve({})),
|
||||
updateApGroup: mock(() => Promise.resolve({})),
|
||||
getAccessPoints: mock(() => Promise.resolve([])),
|
||||
getWifiLimits: mock(() => Promise.resolve({})),
|
||||
getPrivatePSKs: mock(() => Promise.resolve([])),
|
||||
createPrivatePSK: mock(() => Promise.resolve({})),
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped User row for controller tests. */
|
||||
export function buildMockUser(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "user-1",
|
||||
userId: "ms-uid-1",
|
||||
name: "Test User",
|
||||
login: "test@example.com",
|
||||
email: "test@example.com",
|
||||
emailVerified: null,
|
||||
image: null,
|
||||
token: "ms-token",
|
||||
permissions: null,
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
roles: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped Role row. */
|
||||
export function buildMockRole(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "role-1",
|
||||
title: "Test Role",
|
||||
moniker: "test-role",
|
||||
permissions: "mock-permissions-token",
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
users: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped Company row. */
|
||||
export function buildMockCompany(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "company-1",
|
||||
name: "Test Company",
|
||||
cw_Identifier: "TestCo",
|
||||
cw_CompanyId: 123,
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Session row. */
|
||||
export function buildMockSession(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "session-1",
|
||||
sessionKey: "sk-abc123",
|
||||
userId: "user-1",
|
||||
expires: new Date(Date.now() + 30 * 24 * 60 * 60_000),
|
||||
refreshedAt: null,
|
||||
invalidatedAt: null,
|
||||
refreshTokenGenerated: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal CredentialType row. */
|
||||
export function buildMockCredentialType(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "ctype-1",
|
||||
name: "Login Credential",
|
||||
permissionScope: "credential.login",
|
||||
icon: null,
|
||||
fields: [
|
||||
{
|
||||
id: "username",
|
||||
name: "Username",
|
||||
required: true,
|
||||
secure: false,
|
||||
valueType: "plain_text",
|
||||
},
|
||||
{
|
||||
id: "password",
|
||||
name: "Password",
|
||||
required: true,
|
||||
secure: true,
|
||||
valueType: "password",
|
||||
},
|
||||
],
|
||||
credentials: [],
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Credential row. */
|
||||
export function buildMockCredential(overrides: Record<string, any> = {}) {
|
||||
const ctype = buildMockCredentialType();
|
||||
const company = buildMockCompany();
|
||||
return {
|
||||
id: "cred-1",
|
||||
name: "Test Credential",
|
||||
notes: null,
|
||||
typeId: ctype.id,
|
||||
companyId: company.id,
|
||||
subCredentialOfId: null,
|
||||
fields: { username: "admin" },
|
||||
type: ctype,
|
||||
company,
|
||||
securevalues: [
|
||||
{
|
||||
id: "sv-1",
|
||||
name: "password",
|
||||
content: "encrypted-data",
|
||||
hash: "BLAKE2s$abc$salt",
|
||||
credentialId: "cred-1",
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
},
|
||||
],
|
||||
subCredentials: [],
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal UnifiSite row. */
|
||||
export function buildMockUnifiSite(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "usite-1",
|
||||
name: "Main Office",
|
||||
siteId: "default",
|
||||
companyId: null,
|
||||
createdAt: new Date("2025-01-01"),
|
||||
updatedAt: new Date("2025-01-01"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped Opportunity row. */
|
||||
export function buildMockOpportunity(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "opp-1",
|
||||
cwOpportunityId: 1001,
|
||||
name: "Test Opportunity",
|
||||
notes: "Some notes",
|
||||
typeName: "New Business",
|
||||
typeCwId: 1,
|
||||
stageName: "Proposal",
|
||||
stageCwId: 2,
|
||||
statusName: "Active",
|
||||
statusCwId: 3,
|
||||
priorityName: "High",
|
||||
priorityCwId: 4,
|
||||
ratingName: "Hot",
|
||||
ratingCwId: 5,
|
||||
source: "Referral",
|
||||
campaignName: null,
|
||||
campaignCwId: null,
|
||||
primarySalesRepName: "John",
|
||||
primarySalesRepIdentifier: "jroberts",
|
||||
primarySalesRepCwId: 10,
|
||||
secondarySalesRepName: null,
|
||||
secondarySalesRepIdentifier: null,
|
||||
secondarySalesRepCwId: null,
|
||||
companyCwId: 123,
|
||||
companyName: "Test Company",
|
||||
contactCwId: 200,
|
||||
contactName: "Jane Doe",
|
||||
siteCwId: 300,
|
||||
siteName: "Main Office",
|
||||
customerPO: "PO-12345",
|
||||
totalSalesTax: 50.0,
|
||||
locationName: "HQ",
|
||||
locationCwId: 400,
|
||||
departmentName: "Sales",
|
||||
departmentCwId: 500,
|
||||
expectedCloseDate: new Date("2026-04-01"),
|
||||
pipelineChangeDate: new Date("2026-02-15"),
|
||||
dateBecameLead: new Date("2026-01-01"),
|
||||
closedDate: null,
|
||||
closedFlag: false,
|
||||
closedByName: null,
|
||||
closedByCwId: null,
|
||||
companyId: "company-1",
|
||||
cwLastUpdated: new Date("2026-02-28"),
|
||||
createdAt: new Date("2026-01-01"),
|
||||
updatedAt: new Date("2026-02-28"),
|
||||
company: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal CW Activity object for ActivityController tests. */
|
||||
export function buildMockCWActivity(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: 5001,
|
||||
name: "Test Activity",
|
||||
notes: "Activity notes",
|
||||
type: { id: 1, name: "Call" },
|
||||
status: { id: 2, name: "Open" },
|
||||
company: { id: 123, identifier: "TestCo", name: "Test Company" },
|
||||
contact: { id: 200, name: "Jane Doe" },
|
||||
phoneNumber: "555-1234",
|
||||
email: "jane@test.com",
|
||||
opportunity: { id: 1001, name: "Test Opportunity" },
|
||||
ticket: { id: 0, name: "" },
|
||||
agreement: { id: 0, name: "" },
|
||||
campaign: { id: 0, name: "" },
|
||||
assignTo: { id: 10, identifier: "jroberts", name: "John Roberts" },
|
||||
scheduleStatus: { id: 1, name: "Firm" },
|
||||
reminder: { id: 1, name: "15 Minutes" },
|
||||
where: { id: 1, name: "Office" },
|
||||
dateStart: "2026-03-01T09:00:00Z",
|
||||
dateEnd: "2026-03-01T10:00:00Z",
|
||||
notifyFlag: false,
|
||||
mobileGuid: "guid-abc123",
|
||||
currency: { id: 1, name: "USD" },
|
||||
customFields: [],
|
||||
_info: {
|
||||
lastUpdated: "2026-02-28T12:00:00Z",
|
||||
updatedBy: "jroberts",
|
||||
dateEntered: "2026-01-15T08:00:00Z",
|
||||
enteredBy: "jroberts",
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal CW Forecast Item for ForecastProductController tests. */
|
||||
export function buildMockCWForecastItem(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: 7001,
|
||||
forecastDescription: "Network Switch",
|
||||
opportunity: { id: 1001, name: "Test Opportunity" },
|
||||
quantity: 5,
|
||||
status: { id: 1, name: "Won" },
|
||||
catalogItem: { id: 500, identifier: "USW-Pro-24" },
|
||||
productDescription: "UniFi Switch Pro 24",
|
||||
productClass: "Product",
|
||||
forecastType: "Product",
|
||||
revenue: 2500.0,
|
||||
cost: 1800.0,
|
||||
margin: 700.0,
|
||||
percentage: 100,
|
||||
includeFlag: true,
|
||||
linkFlag: false,
|
||||
recurringFlag: false,
|
||||
taxableFlag: true,
|
||||
recurringRevenue: 0,
|
||||
recurringCost: 0,
|
||||
cycles: 0,
|
||||
sequenceNumber: 1,
|
||||
subNumber: 0,
|
||||
quoteWerksQuantity: 0,
|
||||
_info: {
|
||||
lastUpdated: "2026-02-28T12:00:00Z",
|
||||
updatedBy: "jroberts",
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped GeneratedQuotes row. */
|
||||
export function buildMockGeneratedQuote(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "quote-1",
|
||||
quoteRegenData: { theme: "default" },
|
||||
quoteFile: new Uint8Array([0x25, 0x50, 0x44, 0x46]),
|
||||
quoteFileName: "Quote-TestOpp.pdf",
|
||||
opportunityId: "opp-1",
|
||||
createdById: "user-1",
|
||||
createdAt: new Date("2026-03-01"),
|
||||
updatedAt: new Date("2026-03-01"),
|
||||
opportunity: null,
|
||||
createdBy: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a minimal Prisma-shaped CatalogItem row. */
|
||||
export function buildMockCatalogItem(overrides: Record<string, any> = {}) {
|
||||
return {
|
||||
id: "cat-1",
|
||||
cwCatalogId: 500,
|
||||
identifier: "USW-Pro-24",
|
||||
name: "UniFi Switch Pro 24",
|
||||
description: "24-port managed switch",
|
||||
customerDescription: "Enterprise switch",
|
||||
internalNotes: null,
|
||||
category: "Technology",
|
||||
categoryCwId: 18,
|
||||
subcategory: "Network-Switch",
|
||||
subcategoryCwId: 112,
|
||||
manufacturer: "Ubiquiti",
|
||||
manufactureCwId: 248,
|
||||
partNumber: "USW-Pro-24",
|
||||
vendorName: "Ubiquiti Inc",
|
||||
vendorSku: "USW-Pro-24",
|
||||
vendorCwId: 100,
|
||||
price: 500.0,
|
||||
cost: 360.0,
|
||||
inactive: false,
|
||||
salesTaxable: true,
|
||||
onHand: 10,
|
||||
cwLastUpdated: new Date("2026-02-28"),
|
||||
linkedItems: [],
|
||||
createdAt: new Date("2026-01-01"),
|
||||
updatedAt: new Date("2026-02-28"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user