import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { AppDataSource } from '@d8d/shared-utils'; import { PaymentMtService } from '../../src/services/payment.mt.service'; import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt'; /** * 支付模块系统配置集成测试 * 验证PaymentMtService与SystemConfigServiceMt的集成 */ describe('支付模块系统配置集成测试', () => { let paymentMtService: PaymentMtService; let systemConfigService: SystemConfigServiceMt; const testTenantId = 1; beforeEach(async () => { // 确保数据库连接 if (!AppDataSource.isInitialized) { await AppDataSource.initialize(); } paymentMtService = new PaymentMtService(AppDataSource); systemConfigService = new SystemConfigServiceMt(AppDataSource); // 清理测试配置 await cleanupTestConfigs(testTenantId); }); afterEach(async () => { // 清理测试配置 await cleanupTestConfigs(testTenantId); }); async function cleanupTestConfigs(tenantId: number) { const configKeys = [ 'wx.payment.merchant.id', 'wx.mini.app.id', 'wx.payment.v3.key', 'wx.payment.notify.url', 'wx.payment.cert.serial.no', 'wx.payment.public.key', 'wx.payment.private.key' ]; for (const key of configKeys) { await systemConfigService.deleteConfig(key, tenantId); } } describe('系统配置读取功能', () => { it('应该从系统配置获取支付配置', async () => { // 设置测试支付配置 await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID'); await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID'); await systemConfigService.setConfig('wx.payment.v3.key', 'test-v3-key', testTenantId, '测试V3密钥'); await systemConfigService.setConfig('wx.payment.notify.url', 'https://test.com/notify', testTenantId, '测试回调URL'); await systemConfigService.setConfig('wx.payment.cert.serial.no', 'test-serial-no', testTenantId, '测试证书序列号'); await systemConfigService.setConfig('wx.payment.public.key', 'test-public-key', testTenantId, '测试公钥'); await systemConfigService.setConfig('wx.payment.private.key', 'test-private-key', testTenantId, '测试私钥'); // 验证配置读取 const config = await paymentMtService['getPaymentConfig'](testTenantId); expect(config.merchantId).toBe('test-merchant-id'); expect(config.appId).toBe('test-app-id'); expect(config.v3Key).toBe('test-v3-key'); expect(config.notifyUrl).toBe('https://test.com/notify'); expect(config.certSerialNo).toBe('test-serial-no'); expect(config.publicKey).toBe('test-public-key'); expect(config.privateKey).toBe('test-private-key'); }); it('应该支持批量获取支付配置', async () => { // 设置测试配置 await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID'); await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID'); // 批量获取配置 const configs = await systemConfigService.getConfigsByKeys( ['wx.payment.merchant.id', 'wx.mini.app.id'], testTenantId ); expect(configs['wx.payment.merchant.id']).toBe('test-merchant-id'); expect(configs['wx.mini.app.id']).toBe('test-app-id'); }); }); describe('租户配置隔离', () => { const tenant1Id = 1; const tenant2Id = 2; it('应该支持不同租户的独立支付配置', async () => { // 为租户1设置配置 await systemConfigService.setConfig('wx.payment.merchant.id', 'tenant1-merchant-id', tenant1Id, '租户1商户ID'); await systemConfigService.setConfig('wx.mini.app.id', 'tenant1-app-id', tenant1Id, '租户1小程序AppID'); // 为租户2设置不同的配置 await systemConfigService.setConfig('wx.payment.merchant.id', 'tenant2-merchant-id', tenant2Id, '租户2商户ID'); await systemConfigService.setConfig('wx.mini.app.id', 'tenant2-app-id', tenant2Id, '租户2小程序AppID'); // 验证租户1的配置 const tenant1Config = await paymentMtService['getPaymentConfig'](tenant1Id); // 验证租户2的配置 const tenant2Config = await paymentMtService['getPaymentConfig'](tenant2Id); expect(tenant1Config.merchantId).toBe('tenant1-merchant-id'); expect(tenant1Config.appId).toBe('tenant1-app-id'); expect(tenant2Config.merchantId).toBe('tenant2-merchant-id'); expect(tenant2Config.appId).toBe('tenant2-app-id'); // 验证配置隔离 expect(tenant1Config.merchantId).not.toBe(tenant2Config.merchantId); expect(tenant1Config.appId).not.toBe(tenant2Config.appId); }); }); describe('配置回退机制', () => { it('应该在系统配置不存在时回退到环境变量', async () => { // 不设置系统配置,依赖环境变量 // 注意:这里假设环境变量已设置,实际测试时需要确保环境变量存在 try { const config = await paymentMtService['getPaymentConfig'](testTenantId); // 如果环境变量存在,应该能获取到配置 expect(config).toBeDefined(); } catch (error) { // 如果环境变量不存在,应该抛出配置不完整的错误 expect(error).toBeInstanceOf(Error); expect((error as Error).message).toContain('微信支付配置不完整'); } }); it('应该优先使用系统配置', async () => { // 设置系统配置 await systemConfigService.setConfig('wx.payment.merchant.id', 'system-merchant-id', testTenantId, '系统配置商户ID'); // 获取配置,应该优先使用系统配置 const config = await paymentMtService['getPaymentConfig'](testTenantId); // 注意:这里只验证了商户ID,其他配置可能仍然依赖环境变量 expect(config.merchantId).toBe('system-merchant-id'); }); }); describe('PaymentMtService集成', () => { it('应该正确注入SystemConfigServiceMt依赖', () => { // 验证服务实例化 expect(paymentMtService).toBeDefined(); expect(paymentMtService).toBeInstanceOf(PaymentMtService); }); it('应该支持动态配置初始化', async () => { // 验证initializeWxPay方法存在 const initializeMethod = paymentMtService['initializeWxPay']; expect(typeof initializeMethod).toBe('function'); // 验证getPaymentConfig方法存在 const getConfigMethod = paymentMtService['getPaymentConfig']; expect(typeof getConfigMethod).toBe('function'); }); it('应该支持租户ID参数', async () => { // 验证createPayment方法支持tenantId参数 const method = paymentMtService.createPayment; expect(typeof method).toBe('function'); // 验证方法签名包含tenantId参数 expect(method.length).toBeGreaterThanOrEqual(6); }); }); describe('配置验证', () => { it('应该验证配置完整性', async () => { // 不设置任何配置,应该抛出配置不完整的错误 await expect(paymentMtService['getPaymentConfig'](testTenantId)) .rejects .toThrow('微信支付配置不完整'); }); it('应该处理证书字符串格式', async () => { // 设置包含转义字符的证书配置 await systemConfigService.setConfig('wx.payment.public.key', 'test\\npublic\\nkey', testTenantId, '测试公钥'); await systemConfigService.setConfig('wx.payment.private.key', 'test\\nprivate\\nkey', testTenantId, '测试私钥'); // 获取配置并验证格式处理 const config = await paymentMtService['getPaymentConfig'](testTenantId); // 验证转义字符被正确处理 expect(config.publicKey).toBe('test\npublic\nkey'); expect(config.privateKey).toBe('test\nprivate\nkey'); }); }); });