293 lines
16 KiB
TypeScript
293 lines
16 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
describe('premium module source packages', () => {
|
|
const moduleIds = ['paid-core']
|
|
|
|
it('所有授权模块都应可作为独立模块镜像构建', () => {
|
|
for (const moduleId of moduleIds) {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', moduleId)
|
|
const dockerfile = fs.readFileSync(path.join(moduleDir, 'Dockerfile'), 'utf8')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
|
|
expect(fs.existsSync(path.join(moduleDir, 'VERSION.txt'))).toBe(true)
|
|
expect(fs.existsSync(path.join(moduleDir, 'package.json'))).toBe(true)
|
|
expect(fs.existsSync(path.join(moduleDir, 'template-validation.mjs'))).toBe(true)
|
|
expect(dockerfile).toContain('HEALTHCHECK')
|
|
expect(dockerfile).toContain('EXPOSE 8787')
|
|
expect(dockerfile).toContain('template-validation.mjs')
|
|
expect(server).toContain(`const moduleId = '${moduleId}'`)
|
|
expect(server).toContain("url.pathname === '/health'")
|
|
expect(server).not.toContain("status: 'success'")
|
|
}
|
|
})
|
|
|
|
it('paid-core 未接真实穿透 provider 时必须明确返回未配置', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("status: 'provider_not_configured'")
|
|
expect(server).toContain("url.pathname === '/tunnel/start'")
|
|
expect(server).toContain("url.pathname === '/tunnel/status'")
|
|
expect(server).toContain("url.pathname === '/tunnel/stop'")
|
|
expect(server).not.toContain("status: 'success'")
|
|
})
|
|
|
|
it('paid-core 应承接 API 访问功能门禁', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("'apiAccess'")
|
|
expect(server).toContain("'apiAccess:use'")
|
|
expect(server).toContain("'apiAccess:read'")
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板字段保存前校验', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/validate-fields'")
|
|
expect(validation).toContain('validateAndFormatUploadTemplateFields')
|
|
expect(validation).toContain('maxFields: 80')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板保存请求标准化', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/normalize-save'")
|
|
expect(server).toContain('normalizeUploadTemplateSaveRequest')
|
|
expect(server).toContain("action: 'customTemplates:normalizeSave'")
|
|
expect(validation).toContain('normalizeUploadTemplateSaveRequest')
|
|
expect(validation).toContain('ALLOWED_TEMPLATE_STATUSES')
|
|
expect(validation).toContain('ALLOWED_MATERIAL_KINDS')
|
|
for (const field of [
|
|
'name',
|
|
'description',
|
|
'status',
|
|
'materialType',
|
|
'materialKind',
|
|
'fieldGroups',
|
|
'displayConfig',
|
|
'fields',
|
|
]) {
|
|
expect(validation).toContain(`'${field}'`)
|
|
}
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板删除规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/plan-delete'")
|
|
expect(server).toContain("action: 'customTemplates:planDelete'")
|
|
expect(validation).toContain('planUploadTemplateDeleteRequest')
|
|
expect(validation).toContain('TEMPLATE_IN_USE')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板更新规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/plan-update'")
|
|
expect(server).toContain("action: 'customTemplates:planUpdate'")
|
|
expect(validation).toContain('planUploadTemplateUpdateRequest')
|
|
expect(validation).toContain('VERSION_CONFLICT')
|
|
expect(validation).toContain('FIELD_NOT_IN_TEMPLATE')
|
|
expect(validation).toContain('TEMPLATE_STRUCTURE_LOCKED')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板素材字段提交校验', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/validate-template-fields'")
|
|
expect(server).toContain("action: 'customTemplates:validateSubmittedFields'")
|
|
expect(validation).toContain('validateSubmittedTemplateFieldsRequest')
|
|
expect(validation).toContain('UNKNOWN_TEMPLATE_FIELDS')
|
|
expect(validation).toContain('TEMPLATE_REQUIRED_FIELDS_MISSING')
|
|
expect(validation).toContain('TEMPLATE_FIELD_VALIDATION_FAILED')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板素材 metadata 准备和大小检查', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/prepare-metadata'")
|
|
expect(server).toContain("action: 'customTemplates:prepareMaterialMetadata'")
|
|
expect(validation).toContain('prepareMaterialMetadataRequest')
|
|
expect(validation).toContain('STANDARD_MATERIAL_FIELDS')
|
|
expect(validation).toContain('METADATA_TOO_LARGE')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板迁移 metadata 准备和备份计算', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/prepare-migration-metadata'")
|
|
expect(server).toContain("action: 'customTemplates:prepareMigrationMetadata'")
|
|
expect(validation).toContain('prepareTemplateMigrationMetadataRequest')
|
|
expect(validation).toContain('materialFieldValues')
|
|
expect(validation).toContain('templateMigrationBackups')
|
|
expect(validation).toContain('droppedTemplateFields')
|
|
expect(validation).toContain('droppedStandardFields')
|
|
expect(validation).toContain('MIGRATION_BACKUP_STANDARD_FIELDS')
|
|
expect(validation).toContain('CLEARABLE_NON_TARGET_FIELD_DEFAULTS')
|
|
expect(validation).toContain('AUDIO_MATERIAL_FIELDS')
|
|
expect(validation).toContain('normalizeOptionalMaterialColumnValue')
|
|
expect(validation).toContain('TARGET_TEMPLATE_FIELDS_UNRESOLVED')
|
|
expect(validation).toContain('METADATA_TOO_LARGE')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板迁移预览和备份字段影响统计', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/build-migration-preview'")
|
|
expect(server).toContain("action: 'customTemplates:buildMigrationPreview'")
|
|
expect(validation).toContain('buildTemplateMigrationPreviewRequest')
|
|
expect(validation).toContain('STANDARD_FIELD_LABELS')
|
|
expect(validation).toContain('buildPreviewFieldSummary')
|
|
expect(validation).toContain('addPreviewFieldImpact')
|
|
expect(validation).toContain('migrationBackup')
|
|
expect(validation).toContain('migrationPreview')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板迁移批处理规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/plan-migration-batch'")
|
|
expect(server).toContain("action: 'customTemplates:planMigrationBatch'")
|
|
expect(validation).toContain('planTemplateMigrationBatchRequest')
|
|
expect(validation).toContain('DEFAULT_MIGRATION_SAFE_LIMIT')
|
|
expect(validation).toContain('MAX_MIGRATION_FORCE_LIMIT')
|
|
expect(validation).toContain('MIGRATION_CONFIRM_REQUIRED')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板公开列表和素材类型投影', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/project-public-options'")
|
|
expect(server).toContain("action: 'customTemplates:projectPublicOptions'")
|
|
expect(validation).toContain('projectPublicTemplateOptionsRequest')
|
|
expect(validation).toContain('projectTemplateList')
|
|
expect(validation).toContain('projectUploadTemplateList')
|
|
expect(validation).toContain('projectMaterialTypes')
|
|
expect(validation).toContain('filterWritableTemplateFields')
|
|
expect(validation).toContain('stripTemplateMaterialSuffix')
|
|
expect(validation).toContain("`template:${template.id}:${templateName}`")
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板字段填写率统计', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/calculate-field-stats'")
|
|
expect(server).toContain("action: 'customTemplates:calculateFieldStats'")
|
|
expect(validation).toContain('calculateTemplateFieldStatsRequest')
|
|
expect(validation).toContain('hasFilledTemplateFieldValue')
|
|
expect(validation).toContain('parseExistingMetadata')
|
|
expect(validation).toContain('isLowFillRate: fillRate < 30')
|
|
expect(validation).toContain('lowFillRateFields')
|
|
})
|
|
|
|
it('paid-core 应承接素材列表自定义字段搜索规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/plan-custom-search'")
|
|
expect(server).toContain("action: 'customTemplates:planMaterialCustomSearch'")
|
|
expect(validation).toContain('planMaterialCustomSearchRequest')
|
|
expect(validation).toContain('normalizeFieldKeyList')
|
|
expect(validation).toContain('STANDARD_MATERIAL_FIELDS.has(key)')
|
|
})
|
|
|
|
it('paid-core 应承接素材列表搜索和筛选查询计划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/plan-list-query'")
|
|
expect(server).toContain("action: 'customTemplates:planMaterialListQuery'")
|
|
expect(validation).toContain('planMaterialListQueryRequest')
|
|
expect(validation).toContain('standardSearchFields')
|
|
expect(validation).toContain('customSearchFieldKeys')
|
|
expect(validation).toContain('standardHomeFilters')
|
|
expect(validation).toContain('customHomeFilters')
|
|
})
|
|
|
|
it('paid-core 应承接首页自定义筛选字段统计规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/plan-home-filter-counts'")
|
|
expect(server).toContain("action: 'customTemplates:planHomeFilterCounts'")
|
|
expect(validation).toContain('planHomeFilterCustomFieldCountsRequest')
|
|
expect(validation).toContain('MATERIAL_HOME_FILTER_COLUMN_FIELDS')
|
|
expect(validation).toContain('MATERIAL_HOME_FILTER_COLUMN_FIELDS.has(key)')
|
|
})
|
|
|
|
it('paid-core 应承接首页筛选字段统计计划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/materials/plan-home-filter-fields'")
|
|
expect(server).toContain("action: 'customTemplates:planHomeFilterFields'")
|
|
expect(validation).toContain('planHomeFilterFieldCountsRequest')
|
|
expect(validation).toContain('fieldPlans')
|
|
expect(validation).toContain("source: MATERIAL_HOME_FILTER_COLUMN_FIELDS.has(key) ? 'column' : 'metadata'")
|
|
})
|
|
|
|
it('paid-core 应承接部门隔离范围规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/departments/plan-scope'")
|
|
expect(server).toContain("action: 'departmentIsolation:planScope'")
|
|
expect(validation).toContain('planDepartmentScopeRequest')
|
|
expect(validation).toContain('buildDepartmentDescendantSet')
|
|
expect(validation).toContain('withinScope')
|
|
})
|
|
|
|
it('paid-core 应承接部门结构变更规划', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/departments/plan-structure-change'")
|
|
expect(server).toContain("action: 'departmentIsolation:planStructureChange'")
|
|
expect(validation).toContain('planDepartmentStructureChangeRequest')
|
|
expect(validation).toContain('departmentOps')
|
|
expect(validation).toContain('userOps')
|
|
expect(validation).toContain('clearManagedDepartmentIn')
|
|
})
|
|
|
|
it('paid-core 应承接自定义模板结构变更风险判断', () => {
|
|
const moduleDir = path.join(process.cwd(), 'premium-modules', 'paid-core')
|
|
const server = fs.readFileSync(path.join(moduleDir, 'server.mjs'), 'utf8')
|
|
const validation = fs.readFileSync(path.join(moduleDir, 'template-validation.mjs'), 'utf8')
|
|
|
|
expect(server).toContain("url.pathname === '/templates/detect-structure-changes'")
|
|
expect(validation).toContain('detectDangerousTemplateChanges')
|
|
expect(validation).toContain('fieldOptionsRemoved')
|
|
expect(validation).toContain('fieldConditionsChanged')
|
|
})
|
|
})
|