mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 05:11:24 +08:00
test(schema): add comprehensive tests for jsonSchemaToZod function
This commit is contained in:
parent
08777e0746
commit
e89af9042c
340
src/main/apiServer/services/__tests__/jsonSchemaToZod.test.ts
Normal file
340
src/main/apiServer/services/__tests__/jsonSchemaToZod.test.ts
Normal file
@ -0,0 +1,340 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { type JsonSchemaLike, jsonSchemaToZod } from '../unified-messages'
|
||||
|
||||
describe('jsonSchemaToZod', () => {
|
||||
describe('Basic Types', () => {
|
||||
it('should convert string type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'string' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodString)
|
||||
expect(result.safeParse('hello').success).toBe(true)
|
||||
expect(result.safeParse(123).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert string with minLength', () => {
|
||||
const schema: JsonSchemaLike = { type: 'string', minLength: 3 }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('ab').success).toBe(false)
|
||||
expect(result.safeParse('abc').success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert string with maxLength', () => {
|
||||
const schema: JsonSchemaLike = { type: 'string', maxLength: 5 }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('hello').success).toBe(true)
|
||||
expect(result.safeParse('hello world').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert string with pattern', () => {
|
||||
const schema: JsonSchemaLike = { type: 'string', pattern: '^[0-9]+$' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('123').success).toBe(true)
|
||||
expect(result.safeParse('abc').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert number type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'number' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodNumber)
|
||||
expect(result.safeParse(42).success).toBe(true)
|
||||
expect(result.safeParse(3.14).success).toBe(true)
|
||||
expect(result.safeParse('42').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert integer type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'integer' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse(42).success).toBe(true)
|
||||
expect(result.safeParse(3.14).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert number with minimum', () => {
|
||||
const schema: JsonSchemaLike = { type: 'number', minimum: 10 }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse(5).success).toBe(false)
|
||||
expect(result.safeParse(10).success).toBe(true)
|
||||
expect(result.safeParse(15).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert number with maximum', () => {
|
||||
const schema: JsonSchemaLike = { type: 'number', maximum: 100 }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse(50).success).toBe(true)
|
||||
expect(result.safeParse(100).success).toBe(true)
|
||||
expect(result.safeParse(150).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert boolean type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'boolean' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodBoolean)
|
||||
expect(result.safeParse(true).success).toBe(true)
|
||||
expect(result.safeParse(false).success).toBe(true)
|
||||
expect(result.safeParse('true').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert null type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'null' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodNull)
|
||||
expect(result.safeParse(null).success).toBe(true)
|
||||
expect(result.safeParse(undefined).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Enum Types', () => {
|
||||
it('should convert string enum', () => {
|
||||
const schema: JsonSchemaLike = { enum: ['red', 'green', 'blue'] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('red').success).toBe(true)
|
||||
expect(result.safeParse('green').success).toBe(true)
|
||||
expect(result.safeParse('yellow').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert non-string enum with literals', () => {
|
||||
const schema: JsonSchemaLike = { enum: [1, 2, 3] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse(1).success).toBe(true)
|
||||
expect(result.safeParse(2).success).toBe(true)
|
||||
expect(result.safeParse(4).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert single value enum', () => {
|
||||
const schema: JsonSchemaLike = { enum: ['only'] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('only').success).toBe(true)
|
||||
expect(result.safeParse('other').success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert mixed enum', () => {
|
||||
const schema: JsonSchemaLike = { enum: ['text', 1, true] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('text').success).toBe(true)
|
||||
expect(result.safeParse(1).success).toBe(true)
|
||||
expect(result.safeParse(true).success).toBe(true)
|
||||
expect(result.safeParse(false).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Array Types', () => {
|
||||
it('should convert array of strings', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse(['a', 'b']).success).toBe(true)
|
||||
expect(result.safeParse([1, 2]).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert array without items (unknown)', () => {
|
||||
const schema: JsonSchemaLike = { type: 'array' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse([]).success).toBe(true)
|
||||
expect(result.safeParse(['a', 1, true]).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert array with minItems', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'array',
|
||||
items: { type: 'number' },
|
||||
minItems: 2
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse([1]).success).toBe(false)
|
||||
expect(result.safeParse([1, 2]).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert array with maxItems', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'array',
|
||||
items: { type: 'number' },
|
||||
maxItems: 3
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse([1, 2, 3]).success).toBe(true)
|
||||
expect(result.safeParse([1, 2, 3, 4]).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Object Types', () => {
|
||||
it('should convert simple object', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' }
|
||||
}
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse({ name: 'John', age: 30 }).success).toBe(true)
|
||||
expect(result.safeParse({ name: 'John', age: '30' }).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should handle required fields', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' }
|
||||
},
|
||||
required: ['name']
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse({ name: 'John', age: 30 }).success).toBe(true)
|
||||
expect(result.safeParse({ age: 30 }).success).toBe(false)
|
||||
expect(result.safeParse({ name: 'John' }).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert empty object', () => {
|
||||
const schema: JsonSchemaLike = { type: 'object' }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse({}).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should convert nested objects', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
email: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse({ user: { name: 'John', email: 'john@example.com' } }).success).toBe(true)
|
||||
expect(result.safeParse({ user: { name: 'John' } }).success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Union Types', () => {
|
||||
it('should convert union type (type array)', () => {
|
||||
const schema: JsonSchemaLike = { type: ['string', 'null'] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('hello').success).toBe(true)
|
||||
expect(result.safeParse(null).success).toBe(true)
|
||||
expect(result.safeParse(123).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert single type array', () => {
|
||||
const schema: JsonSchemaLike = { type: ['string'] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('hello').success).toBe(true)
|
||||
expect(result.safeParse(123).success).toBe(false)
|
||||
})
|
||||
|
||||
it('should convert multiple union types', () => {
|
||||
const schema: JsonSchemaLike = { type: ['string', 'number', 'boolean'] }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('text').success).toBe(true)
|
||||
expect(result.safeParse(42).success).toBe(true)
|
||||
expect(result.safeParse(true).success).toBe(true)
|
||||
expect(result.safeParse(null).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Description Handling', () => {
|
||||
it('should preserve description for string', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'string',
|
||||
description: 'A user name'
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.description).toBe('A user name')
|
||||
})
|
||||
|
||||
it('should preserve description for enum', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
enum: ['red', 'green', 'blue'],
|
||||
description: 'Available colors'
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.description).toBe('Available colors')
|
||||
})
|
||||
|
||||
it('should preserve description for object', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'object',
|
||||
description: 'User object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.description).toBe('User object')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle unknown type', () => {
|
||||
const schema: JsonSchemaLike = { type: 'unknown-type' as any }
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodType)
|
||||
expect(result.safeParse(anything).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle schema without type', () => {
|
||||
const schema: JsonSchemaLike = {}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result).toBeInstanceOf(z.ZodType)
|
||||
expect(result.safeParse(anything).success).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle complex nested schema', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
tags: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
},
|
||||
required: ['id']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
const validData = {
|
||||
items: [
|
||||
{ id: 1, name: 'Item 1', tags: ['tag1', 'tag2'] },
|
||||
{ id: 2, tags: [] }
|
||||
]
|
||||
}
|
||||
expect(result.safeParse(validData).success).toBe(true)
|
||||
|
||||
const invalidData = {
|
||||
items: [{ name: 'No ID' }]
|
||||
}
|
||||
expect(result.safeParse(invalidData).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('OpenRouter Model IDs', () => {
|
||||
it('should handle model identifier format with colons', () => {
|
||||
const schema: JsonSchemaLike = {
|
||||
type: 'string',
|
||||
enum: ['openrouter:anthropic/claude-3.5-sonnet:free', 'openrouter:gpt-4:paid']
|
||||
}
|
||||
const result = jsonSchemaToZod(schema)
|
||||
expect(result.safeParse('openrouter:anthropic/claude-3.5-sonnet:free').success).toBe(true)
|
||||
expect(result.safeParse('openrouter:gpt-4:paid').success).toBe(true)
|
||||
expect(result.safeParse('other').success).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const anything = Math.random() > 0.5 ? 'string' : Math.random() > 0.5 ? 123 : { a: true }
|
||||
@ -1,7 +1,7 @@
|
||||
import type { AnthropicProviderOptions } from '@ai-sdk/anthropic'
|
||||
import type { GoogleGenerativeAIProviderOptions } from '@ai-sdk/google'
|
||||
import type { OpenAIResponsesProviderOptions } from '@ai-sdk/openai'
|
||||
import type { LanguageModelV2Middleware, LanguageModelV2ToolResultOutput } from '@ai-sdk/provider'
|
||||
import type { JSONSchema7, LanguageModelV2Middleware, LanguageModelV2ToolResultOutput } from '@ai-sdk/provider'
|
||||
import type { ProviderOptions, ReasoningPart, ToolCallPart, ToolResultPart } from '@ai-sdk/provider-utils'
|
||||
import type {
|
||||
ImageBlockParam,
|
||||
@ -143,18 +143,20 @@ function convertAnthropicToolResultToAiSdk(
|
||||
return { type: 'content', value: values }
|
||||
}
|
||||
|
||||
// Type alias for JSON Schema (compatible with recursive calls)
|
||||
type JsonSchemaLike = AnthropicTool.InputSchema | Record<string, unknown>
|
||||
/**
|
||||
* JSON Schema type for tool input schemas
|
||||
* Uses the standard JSONSchema7 type from the json-schema package (via @ai-sdk/provider)
|
||||
*/
|
||||
export type JsonSchemaLike = JSONSchema7
|
||||
|
||||
/**
|
||||
* Convert JSON Schema to Zod schema
|
||||
* This avoids non-standard fields like input_examples that Anthropic doesn't support
|
||||
*/
|
||||
function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
const s = schema as Record<string, unknown>
|
||||
const schemaType = s.type as string | string[] | undefined
|
||||
const enumValues = s.enum as unknown[] | undefined
|
||||
const description = s.description as string | undefined
|
||||
export function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
const schemaType = schema.type
|
||||
const enumValues = schema.enum
|
||||
const description = schema.description
|
||||
|
||||
// Handle enum first
|
||||
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) {
|
||||
@ -173,7 +175,13 @@ function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
|
||||
// Handle union types (type: ["string", "null"])
|
||||
if (Array.isArray(schemaType)) {
|
||||
const schemas = schemaType.map((t) => jsonSchemaToZod({ ...s, type: t, enum: undefined }))
|
||||
const schemas = schemaType.map((t) =>
|
||||
jsonSchemaToZod({
|
||||
...schema,
|
||||
type: t,
|
||||
enum: undefined
|
||||
})
|
||||
)
|
||||
if (schemas.length === 1) {
|
||||
return schemas[0]
|
||||
}
|
||||
@ -184,17 +192,17 @@ function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
switch (schemaType) {
|
||||
case 'string': {
|
||||
let zodString = z.string()
|
||||
if (typeof s.minLength === 'number') zodString = zodString.min(s.minLength)
|
||||
if (typeof s.maxLength === 'number') zodString = zodString.max(s.maxLength)
|
||||
if (typeof s.pattern === 'string') zodString = zodString.regex(new RegExp(s.pattern))
|
||||
if (typeof schema.minLength === 'number') zodString = zodString.min(schema.minLength)
|
||||
if (typeof schema.maxLength === 'number') zodString = zodString.max(schema.maxLength)
|
||||
if (typeof schema.pattern === 'string') zodString = zodString.regex(new RegExp(schema.pattern))
|
||||
return description ? zodString.describe(description) : zodString
|
||||
}
|
||||
|
||||
case 'number':
|
||||
case 'integer': {
|
||||
let zodNumber = schemaType === 'integer' ? z.number().int() : z.number()
|
||||
if (typeof s.minimum === 'number') zodNumber = zodNumber.min(s.minimum)
|
||||
if (typeof s.maximum === 'number') zodNumber = zodNumber.max(s.maximum)
|
||||
if (typeof schema.minimum === 'number') zodNumber = zodNumber.min(schema.minimum)
|
||||
if (typeof schema.maximum === 'number') zodNumber = zodNumber.max(schema.maximum)
|
||||
return description ? zodNumber.describe(description) : zodNumber
|
||||
}
|
||||
|
||||
@ -207,24 +215,33 @@ function jsonSchemaToZod(schema: JsonSchemaLike): z.ZodTypeAny {
|
||||
return z.null()
|
||||
|
||||
case 'array': {
|
||||
const items = s.items as Record<string, unknown> | undefined
|
||||
let zodArray = items ? z.array(jsonSchemaToZod(items)) : z.array(z.unknown())
|
||||
if (typeof s.minItems === 'number') zodArray = zodArray.min(s.minItems)
|
||||
if (typeof s.maxItems === 'number') zodArray = zodArray.max(s.maxItems)
|
||||
const items = schema.items
|
||||
let zodArray: z.ZodArray<z.ZodTypeAny>
|
||||
if (items && typeof items === 'object' && !Array.isArray(items)) {
|
||||
zodArray = z.array(jsonSchemaToZod(items as JsonSchemaLike))
|
||||
} else {
|
||||
zodArray = z.array(z.unknown())
|
||||
}
|
||||
if (typeof schema.minItems === 'number') zodArray = zodArray.min(schema.minItems)
|
||||
if (typeof schema.maxItems === 'number') zodArray = zodArray.max(schema.maxItems)
|
||||
return description ? zodArray.describe(description) : zodArray
|
||||
}
|
||||
|
||||
case 'object': {
|
||||
const properties = s.properties as Record<string, Record<string, unknown>> | undefined
|
||||
const required = (s.required as string[]) || []
|
||||
const properties = schema.properties
|
||||
const required = schema.required || []
|
||||
|
||||
// Always use z.object() to ensure "properties" field is present in output schema
|
||||
// OpenAI requires explicit properties field even for empty objects
|
||||
const shape: Record<string, z.ZodTypeAny> = {}
|
||||
if (properties) {
|
||||
if (properties && typeof properties === 'object') {
|
||||
for (const [key, propSchema] of Object.entries(properties)) {
|
||||
const zodProp = jsonSchemaToZod(propSchema)
|
||||
shape[key] = required.includes(key) ? zodProp : zodProp.optional()
|
||||
if (typeof propSchema === 'boolean') {
|
||||
shape[key] = propSchema ? z.unknown() : z.never()
|
||||
} else {
|
||||
const zodProp = jsonSchemaToZod(propSchema as JsonSchemaLike)
|
||||
shape[key] = required.includes(key) ? zodProp : zodProp.optional()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +263,8 @@ function convertAnthropicToolsToAiSdk(tools: MessageCreateParams['tools']): Reco
|
||||
if (anthropicTool.type === 'bash_20250124') continue
|
||||
const toolDef = anthropicTool as AnthropicTool
|
||||
const rawSchema = toolDef.input_schema
|
||||
const schema = jsonSchemaToZod(rawSchema)
|
||||
// Convert Anthropic's InputSchema to JSONSchema7-compatible format
|
||||
const schema = jsonSchemaToZod(rawSchema as JsonSchemaLike)
|
||||
|
||||
// Use tool() with inputSchema (AI SDK v5 API)
|
||||
const aiTool = tool({
|
||||
|
||||
@ -61,7 +61,19 @@ vi.mock('electron', () => ({
|
||||
getPrimaryDisplay: vi.fn(),
|
||||
getAllDisplays: vi.fn()
|
||||
},
|
||||
Notification: vi.fn()
|
||||
Notification: vi.fn(),
|
||||
net: {
|
||||
fetch: vi.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
json: vi.fn(() => Promise.resolve({})),
|
||||
text: vi.fn(() => Promise.resolve('')),
|
||||
headers: new Headers()
|
||||
})
|
||||
)
|
||||
}
|
||||
}))
|
||||
|
||||
// Mock Winston for LoggerService dependencies
|
||||
@ -97,15 +109,40 @@ vi.mock('winston-daily-rotate-file', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
// Mock Node.js modules
|
||||
vi.mock('node:os', () => ({
|
||||
platform: vi.fn(() => 'darwin'),
|
||||
arch: vi.fn(() => 'x64'),
|
||||
version: vi.fn(() => '20.0.0'),
|
||||
cpus: vi.fn(() => [{ model: 'Mock CPU' }]),
|
||||
totalmem: vi.fn(() => 8 * 1024 * 1024 * 1024) // 8GB
|
||||
// Mock main process services
|
||||
vi.mock('@main/services/AnthropicService', () => ({
|
||||
default: {}
|
||||
}))
|
||||
|
||||
vi.mock('@main/services/CopilotService', () => ({
|
||||
default: {}
|
||||
}))
|
||||
|
||||
vi.mock('@main/services/ReduxService', () => ({
|
||||
reduxService: {
|
||||
selectSync: vi.fn()
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('@main/integration/cherryai', () => ({
|
||||
generateSignature: vi.fn()
|
||||
}))
|
||||
|
||||
// Mock Node.js modules
|
||||
vi.mock('node:os', async () => {
|
||||
const actual = await vi.importActual<typeof import('node:os')>('node:os')
|
||||
return {
|
||||
...actual,
|
||||
default: actual,
|
||||
platform: vi.fn(() => 'darwin'),
|
||||
arch: vi.fn(() => 'x64'),
|
||||
version: vi.fn(() => '20.0.0'),
|
||||
cpus: vi.fn(() => [{ model: 'Mock CPU' }]),
|
||||
totalmem: vi.fn(() => 8 * 1024 * 1024 * 1024), // 8GB
|
||||
homedir: vi.fn(() => '/tmp')
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('node:path', async () => {
|
||||
const actual = await vi.importActual('node:path')
|
||||
return {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user