feat: 使用env-paths替代platform-folders,增强跨平台用户目录支持,新增标准目录获取方法
This commit is contained in:
276
src/tests/issues/platform-folders.e2e.test.js
Normal file
276
src/tests/issues/platform-folders.e2e.test.js
Normal file
@ -0,0 +1,276 @@
|
||||
const { execSync, spawn } = require('child_process')
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const os = require('os')
|
||||
|
||||
describe('Platform-Folders 兼容性问题 - E2E Tests', () => {
|
||||
let tempDir
|
||||
let originalPlatform
|
||||
|
||||
beforeAll(async () => {
|
||||
// 创建临时目录用于测试
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'promptx-platform-test-'))
|
||||
originalPlatform = process.platform
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (tempDir) {
|
||||
await fs.remove(tempDir)
|
||||
}
|
||||
// 恢复原始平台
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 模拟Windows环境
|
||||
*/
|
||||
function mockWindowsEnvironment() {
|
||||
// 模拟Windows平台
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'win32',
|
||||
configurable: true
|
||||
})
|
||||
|
||||
// 模拟Windows环境变量
|
||||
const originalEnv = { ...process.env }
|
||||
process.env.APPDATA = 'C:\\Users\\Test\\AppData\\Roaming'
|
||||
process.env.LOCALAPPDATA = 'C:\\Users\\Test\\AppData\\Local'
|
||||
process.env.USERPROFILE = 'C:\\Users\\Test'
|
||||
|
||||
return () => {
|
||||
// 恢复环境变量
|
||||
Object.keys(originalEnv).forEach(key => {
|
||||
process.env[key] = originalEnv[key]
|
||||
})
|
||||
Object.keys(process.env).forEach(key => {
|
||||
if (!(key in originalEnv)) {
|
||||
delete process.env[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟platform-folders包导入失败
|
||||
*/
|
||||
function mockPlatformFoldersFailure() {
|
||||
const Module = require('module')
|
||||
const originalRequire = Module.prototype.require
|
||||
|
||||
// Mock Module.prototype.require
|
||||
Module.prototype.require = function(id) {
|
||||
if (id === 'platform-folders') {
|
||||
const error = new Error("Cannot find module 'platform-folders'")
|
||||
error.code = 'MODULE_NOT_FOUND'
|
||||
throw error
|
||||
}
|
||||
return originalRequire.call(this, id)
|
||||
}
|
||||
|
||||
return () => {
|
||||
Module.prototype.require = originalRequire
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟NPX环境下的安装问题
|
||||
*/
|
||||
function mockNpxEnvironment() {
|
||||
const originalEnv = { ...process.env }
|
||||
|
||||
// 模拟npx环境变量
|
||||
process.env.npm_execpath = '/usr/local/lib/node_modules/npm/bin/npx-cli.js'
|
||||
process.env.npm_config_cache = '/tmp/_npx/12345'
|
||||
process.env.npm_lifecycle_event = undefined
|
||||
|
||||
return () => {
|
||||
Object.keys(originalEnv).forEach(key => {
|
||||
process.env[key] = originalEnv[key]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
describe('Windows环境兼容性测试', () => {
|
||||
test('应该检测到Windows环境下的platform-folders问题', async () => {
|
||||
const restoreEnv = mockWindowsEnvironment()
|
||||
const restoreRequire = mockPlatformFoldersFailure()
|
||||
|
||||
try {
|
||||
// 动态导入UserProtocol,测试platform-folders错误处理
|
||||
const UserProtocol = require('../../lib/core/resource/protocols/UserProtocol')
|
||||
const userProtocol = new UserProtocol()
|
||||
|
||||
// 调用可能触发platform-folders的方法
|
||||
const result = await userProtocol.getUserDirectory('home')
|
||||
|
||||
// 验证fallback机制是否工作
|
||||
expect(result).toBeDefined()
|
||||
expect(typeof result).toBe('string')
|
||||
|
||||
// 验证是否使用了fallback路径(home目录应该存在)
|
||||
expect(result).toBeTruthy()
|
||||
} catch (error) {
|
||||
// 如果抛出错误,验证错误信息是否包含platform-folders相关内容
|
||||
expect(error.message).toMatch(/platform-folders|用户目录|配置路径/)
|
||||
} finally {
|
||||
restoreEnv()
|
||||
restoreRequire()
|
||||
}
|
||||
})
|
||||
|
||||
test('应该在Windows + NPX环境下正常工作(无警告)', async () => {
|
||||
const restoreEnv = mockWindowsEnvironment()
|
||||
const restoreNpx = mockNpxEnvironment()
|
||||
|
||||
// 捕获console.warn输出
|
||||
const originalWarn = console.warn
|
||||
const warnMessages = []
|
||||
console.warn = (...args) => {
|
||||
warnMessages.push(args.join(' '))
|
||||
}
|
||||
|
||||
try {
|
||||
// 测试在Windows + NPX环境下env-paths正常工作
|
||||
const UserProtocol = require('../../lib/core/resource/protocols/UserProtocol')
|
||||
const userProtocol = new UserProtocol()
|
||||
|
||||
const documentsPath = await userProtocol.getUserDirectory('documents')
|
||||
|
||||
// 验证获取目录成功
|
||||
expect(documentsPath).toBeDefined()
|
||||
expect(typeof documentsPath).toBe('string')
|
||||
expect(documentsPath.length).toBeGreaterThan(0)
|
||||
|
||||
// 检查是否有platform-folders相关警告
|
||||
const hasPlatformFoldersWarning = warnMessages.some(msg =>
|
||||
msg.includes('platform-folders') ||
|
||||
msg.includes('不可用,使用os.homedir()回退方案')
|
||||
)
|
||||
|
||||
// 使用env-paths后,不应该有platform-folders相关警告
|
||||
expect(hasPlatformFoldersWarning).toBe(false)
|
||||
|
||||
console.log('✅ Windows + NPX环境下env-paths工作正常,无platform-folders警告')
|
||||
|
||||
} finally {
|
||||
console.warn = originalWarn
|
||||
restoreEnv()
|
||||
restoreNpx()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('替代方案验证测试', () => {
|
||||
test('应该验证env-paths作为替代方案可以正常工作', async () => {
|
||||
// 创建一个模拟的env-paths实现
|
||||
const mockEnvPaths = (name) => ({
|
||||
data: path.join(os.homedir(), '.local', 'share', name),
|
||||
config: path.join(os.homedir(), '.config', name),
|
||||
cache: path.join(os.homedir(), '.cache', name),
|
||||
log: path.join(os.homedir(), '.local', 'share', name, 'logs'),
|
||||
temp: path.join(os.tmpdir(), name)
|
||||
})
|
||||
|
||||
// 验证env-paths风格的路径解析
|
||||
const paths = mockEnvPaths('promptx')
|
||||
|
||||
expect(paths.data).toBeDefined()
|
||||
expect(paths.config).toBeDefined()
|
||||
expect(paths.cache).toBeDefined()
|
||||
expect(typeof paths.data).toBe('string')
|
||||
expect(paths.data).toContain('promptx')
|
||||
})
|
||||
|
||||
test('应该测试跨平台路径解析的一致性', () => {
|
||||
// 测试不同平台下的路径格式
|
||||
const testPlatforms = ['win32', 'darwin', 'linux']
|
||||
|
||||
testPlatforms.forEach(platform => {
|
||||
const originalPlatform = process.platform
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: platform,
|
||||
configurable: true
|
||||
})
|
||||
|
||||
try {
|
||||
// 测试路径解析逻辑
|
||||
const homedir = os.homedir()
|
||||
const configPath = path.join(homedir, '.config', 'promptx')
|
||||
|
||||
expect(configPath).toBeDefined()
|
||||
expect(path.isAbsolute(configPath)).toBe(true)
|
||||
|
||||
// 验证路径包含正确的组件
|
||||
expect(configPath).toContain('promptx')
|
||||
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform,
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('实际CLI命令测试', () => {
|
||||
test('在模拟的问题环境下CLI应该仍能正常工作', async () => {
|
||||
const restoreEnv = mockWindowsEnvironment()
|
||||
|
||||
try {
|
||||
// 运行CLI命令,验证即使在问题环境下也能工作
|
||||
const result = execSync('node src/bin/promptx.js hello', {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
timeout: 10000,
|
||||
env: process.env
|
||||
})
|
||||
|
||||
// 验证命令执行成功
|
||||
expect(result).toContain('AI专业角色服务清单')
|
||||
|
||||
} catch (error) {
|
||||
// 如果命令失败,检查是否是由于platform-folders问题
|
||||
const isplatformFoldersError = error.message.includes('platform-folders') ||
|
||||
error.stderr?.includes('platform-folders')
|
||||
|
||||
if (isplatformFoldersError) {
|
||||
console.log('✅ 成功重现了 platform-folders 问题')
|
||||
expect(isplatformFoldersError).toBe(true)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
} finally {
|
||||
restoreEnv()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('错误处理和恢复测试', () => {
|
||||
test('应该测试graceful fallback机制', async () => {
|
||||
const restoreRequire = mockPlatformFoldersFailure()
|
||||
|
||||
try {
|
||||
// 重新导入模块以测试fallback
|
||||
const userProtocolPath = path.resolve(__dirname, '../../lib/core/resource/protocols/UserProtocol.js')
|
||||
delete require.cache[userProtocolPath]
|
||||
const UserProtocol = require('../../lib/core/resource/protocols/UserProtocol')
|
||||
const userProtocol = new UserProtocol()
|
||||
|
||||
// 测试fallback路径生成
|
||||
const fallbackPath = await userProtocol.getUserDirectory('home')
|
||||
|
||||
expect(fallbackPath).toBeDefined()
|
||||
expect(typeof fallbackPath).toBe('string')
|
||||
|
||||
// 验证fallback路径是合理的(home目录应该存在)
|
||||
expect(fallbackPath).toBeTruthy()
|
||||
|
||||
} finally {
|
||||
restoreRequire()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user