api-server/test/mocks/prisma.mock.ts
WangDL 292e7e5638
Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 33s
feat: M2-01 — User & Account deepening, membership + deletion + devices
- UserDevice + AccountDeletionRequest Prisma models
- CAPI: membership query, deletion request/cancel, device list/remove
- AAPI: membership assign, deletion approve/reject, device view

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 11:18:56 +08:00

144 lines
5.0 KiB
TypeScript

// Mock @prisma/client for E2E tests.
// PrismaService extends PrismaClient → this must be a plain class.
// Model access (prisma.user.findMany()) is supported via prototype delegates.
function modelMethods(): Record<string, Function> {
return {
findUnique: () => Promise.resolve(null),
findFirst: () => Promise.resolve(null),
findMany: () => Promise.resolve([]),
findRaw: () => Promise.resolve([]),
create: (args: any) => Promise.resolve({ id: 1, ...args?.data }),
update: (args: any) => Promise.resolve({ id: 1, ...args?.data }),
delete: () => Promise.resolve({ id: 1 }),
upsert: (args: any) => Promise.resolve({ id: 1, ...args?.create }),
count: () => Promise.resolve(0),
aggregate: () => Promise.resolve({}),
groupBy: () => Promise.resolve([]),
createMany: () => Promise.resolve({ count: 1 }),
deleteMany: () => Promise.resolve({ count: 0 }),
updateMany: () => Promise.resolve({ count: 0 }),
aggregateRaw: () => Promise.resolve([]),
}
}
function createModelDelegate(): any {
const methods = modelMethods()
return new Proxy(methods, {
get(target: any, prop: string) {
if (prop === 'then') return undefined
if (prop in target) return target[prop]
return () => Promise.resolve(undefined)
},
})
}
// admin user fixture so login tests can get a real JWT
const ADMIN_USER = {
id: 'admin-test-001',
email: 'admin@zhixi.app',
displayName: 'Test Admin',
passwordHash: '$2b$10$mp8kF.PwWBjb0fp/5d0nZ.VNofYcVm7jhJYtswxLfGU/EJW5K8qCm', // bcrypt hash of "admin123"
role: 'SUPER_ADMIN',
status: 'ACTIVE',
twoFactorEnabled: false,
failedLoginCount: 0,
lockedUntil: null,
deletedAt: null,
lastLoginAt: null,
lastLoginIp: null,
createdAt: new Date(),
updatedAt: new Date(),
}
const ADMIN_SESSION = {
id: 1,
adminUserId: 'admin-test-001',
refreshTokenHash: 'test-hash',
ip: null,
userAgent: null,
revokedAt: null,
expiresAt: new Date(Date.now() + 7 * 86400000),
createdAt: new Date(),
}
export class PrismaClient {
$connect() { return Promise.resolve() }
$disconnect() { return Promise.resolve() }
$on() {}
$transaction(fn: any) {
const delegate = createModelDelegate()
return typeof fn === 'function' ? fn(delegate) : Promise.resolve([])
}
$executeRaw() { return Promise.resolve(0) }
$queryRaw() { return Promise.resolve([]) }
$runCommandRaw() { return Promise.resolve({}) }
}
const modelNames = [
'user', 'authAccount', 'refreshToken', 'userProfile', 'userPreference',
'userConsent', 'knowledgeBase', 'knowledgeItem', 'knowledgeItemRelation',
'tag', 'knowledgeItemTag', 'uploadedFile', 'documentImport',
'learningSession', 'learningRecord', 'activeRecallQuestion',
'activeRecallAnswer', 'aiAnalysisJob', 'aiAnalysisResult', 'focusItem',
'reviewCard', 'reviewLog', 'reviewPlan', 'dailyLearningActivity',
'notification', 'feedback', 'aiUsageLog', 'waitlistEntry', 'appChangelog',
'knowledgeSource', 'knowledgeChunk', 'importCandidate', 'backupJob',
'adminUser', 'adminSession', 'adminAuditLog', 'membershipPlan',
'adminConversation', 'adminMessage', 'adminCostItem', 'appConfig',
'featureFlag', 'configChangeLog', 'securityEvent', 'sensitiveWord',
'contentSafetyCheck', 'contentReport', 'apiMetric', 'taskLog',
'userMembership', 'quotaUsage', 'costDailySummary', 'secretRecord',
'secretAccessLog', 'modelRoute', 'providerConfig', 'fallbackEvent',
'violationRecord', 'contentReport', 'userDevice', 'accountDeletionRequest',
]
for (const name of modelNames) {
;(PrismaClient.prototype as any)[name] = createModelDelegate()
}
// Patch adminUser.findUnique so login tests can succeed
const origAdminUser = (PrismaClient.prototype as any).adminUser
;(PrismaClient.prototype as any).adminUser = new Proxy(origAdminUser, {
get(target: any, prop: string) {
if (prop === 'findUnique') {
return (args: any) => {
if (args?.where?.email === ADMIN_USER.email) return Promise.resolve(ADMIN_USER)
if (args?.where?.id === ADMIN_USER.id) return Promise.resolve(ADMIN_USER)
return target.findUnique(args)
}
}
if (prop === 'findFirst') {
return (args: any) => {
if (args?.where?.email === ADMIN_USER.email) return Promise.resolve(ADMIN_USER)
return target.findFirst(args)
}
}
return target[prop]
},
})
// Patch adminSession so admin auth guard doesn't reject
const origAdminSession = (PrismaClient.prototype as any).adminSession
;(PrismaClient.prototype as any).adminSession = new Proxy(origAdminSession, {
get(target: any, prop: string) {
if (prop === 'findUnique' || prop === 'findFirst') {
return (_args?: any) => Promise.resolve(ADMIN_SESSION)
}
return target[prop]
},
})
export const Prisma = {
ModelName: {},
PrismaClientKnownRequestError: class extends Error {
code: string
constructor(message: string, opts: { code: string; clientVersion: string }) {
super(message)
this.code = opts.code
}
},
PrismaClientValidationError: class extends Error {},
PrismaClientInitializationError: class extends Error {},
}