forked from wangziqi/gongxue-base
test: guard taro persona flows
This commit is contained in:
370
scripts/taro-persona-contract-test.js
Normal file
370
scripts/taro-persona-contract-test.js
Normal file
@@ -0,0 +1,370 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const taroSrc = path.join(repoRoot, 'apps', 'taro', 'src');
|
||||
|
||||
const contracts = [
|
||||
{
|
||||
id: 'student.home-launcher',
|
||||
file: 'pages/student/home/index.tsx',
|
||||
mustContain: [
|
||||
'loadStudentDashboard',
|
||||
'loadCurrentUser',
|
||||
'/pages/student/catalog/index',
|
||||
'/pages/student/review/index',
|
||||
'/pages/student/profile/index',
|
||||
'/pages/student/assets/index',
|
||||
],
|
||||
mustNotContain: ['loadLeaderboard', 'leaderboard', '排行榜'],
|
||||
},
|
||||
{
|
||||
id: 'student.catalog-to-practice',
|
||||
file: 'pages/student/catalog/index.tsx',
|
||||
mustContain: [
|
||||
'loadContentEntries',
|
||||
'loadContentNodes',
|
||||
'loadQuestionCollections',
|
||||
'loadPracticeBlueprints',
|
||||
'/pages/student/practice/index?',
|
||||
'collectionId=',
|
||||
'blueprintId=',
|
||||
'mode=',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'student.practice-svip-loop',
|
||||
file: 'pages/student/practice/index.tsx',
|
||||
mustContain: [
|
||||
'createPracticeSession',
|
||||
'loadPracticeSessionDetail',
|
||||
'submitAnswer',
|
||||
'submitPracticeSession',
|
||||
'toggleQuestionFavorite',
|
||||
'submitFeedback',
|
||||
'loadCollectionQuestions',
|
||||
'loadQuestions',
|
||||
'answerStorageKey',
|
||||
'indexStorageKey',
|
||||
'selfJudgedCorrect',
|
||||
'subAnswers',
|
||||
'/pages/student/reports/index?practiceSessionId=',
|
||||
'/pages/student/review/index?type=wrong',
|
||||
'/pages/student/video/index?questionId=',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'student.review-wrong-favorite',
|
||||
file: 'pages/student/review/index.tsx',
|
||||
mustContain: [
|
||||
'loadWrongQuestionReviewPlan',
|
||||
'loadFavoriteQuestions',
|
||||
'resolveWrongQuestion',
|
||||
'wrong_review',
|
||||
'favorite_review',
|
||||
'/pages/student/practice/index?mode=',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'student.checkout-svip-order',
|
||||
file: 'pages/student/checkout/index.tsx',
|
||||
mustContain: [
|
||||
'loadSvipPlans',
|
||||
'claimCoupon',
|
||||
'createOrder',
|
||||
'createPayment',
|
||||
'loadOrderStatus',
|
||||
'Taro.requestPayment',
|
||||
'/pages/student/order-detail/index?orderNo=',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'student.profile-center',
|
||||
file: 'pages/student/profile/index.tsx',
|
||||
mustContain: [
|
||||
'loadProfile',
|
||||
'loadEntitlements',
|
||||
'loadLearningStats',
|
||||
'loadPracticeHistory',
|
||||
'checkActivationCode',
|
||||
'redeemActivationCode',
|
||||
'loadNotifications',
|
||||
'updateNotificationStatus',
|
||||
'loadBadges',
|
||||
'avatarPreset',
|
||||
'/pages/student/review/index?type=wrong',
|
||||
'/pages/student/review/index?type=favorite',
|
||||
'/pages/student/checkout/index',
|
||||
],
|
||||
mustNotContain: ['chooseImage', 'uploadFile', 'avatarUrl', 'headimgurl', 'figureurl'],
|
||||
},
|
||||
{
|
||||
id: 'tenant.workbench-permission-modules',
|
||||
file: 'pages/tenant-admin/workbench/index.tsx',
|
||||
mustContain: [
|
||||
'loadTenantPermissions',
|
||||
'canOpenModule',
|
||||
'/pages/tenant-admin/dashboard/index',
|
||||
'/pages/tenant-admin/students/index',
|
||||
'/pages/tenant-admin/content/index',
|
||||
'/pages/tenant-admin/marketing/index',
|
||||
'/pages/tenant-admin/finance/index',
|
||||
'/pages/tenant-admin/settings/index',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tenant.students-ops-crm-supervision',
|
||||
file: 'pages/tenant-admin/students/index.tsx',
|
||||
mustContain: [
|
||||
'loadTenantStudents',
|
||||
'upsertTenantStudent',
|
||||
'bulkUpsertTenantStudents',
|
||||
'bulkAssignTenantClassMembers',
|
||||
'updateTenantStudentStatus',
|
||||
'upsertTenantStudentNote',
|
||||
'upsertTenantStudentFollowup',
|
||||
'previewTenantStudentSupervision',
|
||||
'generateTenantStudentSupervision',
|
||||
'upsertTenantStudentSupervisionRule',
|
||||
'pushTenantStudentsToCrm',
|
||||
],
|
||||
mustNotContain: ['avatarUrl', 'headimgurl', 'figureurl', 'primaryRole'],
|
||||
},
|
||||
{
|
||||
id: 'tenant.content-import-public-bank',
|
||||
file: 'pages/tenant-admin/content/index.tsx',
|
||||
mustContain: [
|
||||
'previewContentImport',
|
||||
'executeContentImport',
|
||||
'loadImportJobs',
|
||||
'loadImportJobDetail',
|
||||
'loadImportIssues',
|
||||
'loadImportFieldMapping',
|
||||
'loadImportTemplate',
|
||||
'runImportPostCheck',
|
||||
'loadPublicQuestionBanks',
|
||||
'adoptPublicQuestionBank',
|
||||
'syncPublicQuestionBank',
|
||||
'loadPublicQuestionBankConflicts',
|
||||
'resolvePublicQuestionBankConflict',
|
||||
'resolvePublicQuestionBankConflicts',
|
||||
'loadTenantContentNotifications',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tenant.marketing-commerce-growth',
|
||||
file: 'pages/tenant-admin/marketing/index.tsx',
|
||||
mustContain: [
|
||||
'loadCoupons',
|
||||
'upsertCoupon',
|
||||
'loadCouponRedemptions',
|
||||
'loadCouponReport',
|
||||
'loadCrmConfig',
|
||||
'upsertCrmConfig',
|
||||
'loadCrmQueue',
|
||||
'loadCrmDeadLetters',
|
||||
'updateCrmQueueAction',
|
||||
'loadReferralConversionReport',
|
||||
'loadCommissionSettings',
|
||||
'updateCommissionSettings',
|
||||
'generateCommissionSettlement',
|
||||
'updateCommissionSettlementStatus',
|
||||
'createCommissionSettlementProof',
|
||||
'upsertPointActivityTask',
|
||||
'upsertPointExchangeItem',
|
||||
'loadUserNotifications',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tenant.finance-reconciliation',
|
||||
file: 'pages/tenant-admin/finance/index.tsx',
|
||||
mustContain: [
|
||||
'loadTenantRefunds',
|
||||
'createTenantRefund',
|
||||
'updateTenantRefundStatus',
|
||||
'requestProviderBillDownload',
|
||||
'loadProviderBillJobs',
|
||||
'loadReconciliationBatches',
|
||||
'loadReconciliationItems',
|
||||
'createReconciliationIssue',
|
||||
'updateReconciliationIssueStatus',
|
||||
'loadCommerceOperationAnomalies',
|
||||
'createAdjustmentVoucher',
|
||||
'updateAdjustmentVoucherStatus',
|
||||
'loadAdjustmentVoucherReport',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tenant.settings-brand-auth-role',
|
||||
file: 'pages/tenant-admin/settings/index.tsx',
|
||||
mustContain: [
|
||||
'loadTenantOverview',
|
||||
'loadTenantDomains',
|
||||
'loadPaymentAccounts',
|
||||
'loadAuthProviders',
|
||||
'loadThemeTemplates',
|
||||
'loadTenantTheme',
|
||||
'previewTenantTheme',
|
||||
'publishTenantTheme',
|
||||
'loadTenantPermissions',
|
||||
'loadRoleTemplates',
|
||||
'upsertRoleTemplate',
|
||||
'disableRoleTemplate',
|
||||
'loadTenantMembers',
|
||||
'upsertTenantMember',
|
||||
'disableTenantMember',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform.workbench-governance',
|
||||
file: 'pages/platform-admin/workbench/index.tsx',
|
||||
mustContain: [
|
||||
'loadPlatformOverview',
|
||||
'loadPlatformTenants',
|
||||
'loadPlatformInvoices',
|
||||
'loadPlatformQuestionBanks',
|
||||
'loadPlatformQuestionBankGrants',
|
||||
'loadPlatformAuditLogs',
|
||||
'exportPlatformAuditLogs',
|
||||
'loadPlatformAuditAlerts',
|
||||
'updatePlatformAuditAlertStatus',
|
||||
'loadPlatformAuditNotificationChannels',
|
||||
'loadPlatformDunningNotificationChannels',
|
||||
'/pages/platform-admin/tenants/index',
|
||||
'/pages/platform-admin/billing/index',
|
||||
'/pages/platform-admin/question-banks/index',
|
||||
'/pages/platform-admin/staff/index',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform.tenant-lifecycle',
|
||||
file: 'pages/platform-admin/tenants/index.tsx',
|
||||
mustContain: [
|
||||
'loadPlatformPlans',
|
||||
'loadPlatformTenants',
|
||||
'createPlatformTenant',
|
||||
'loadPlatformTenantDetail',
|
||||
'updatePlatformTenantStatus',
|
||||
'upsertPlatformTenantBillingProfile',
|
||||
'loadPlatformAuditLogs',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform.billing-usage-dunning',
|
||||
file: 'pages/platform-admin/billing/index.tsx',
|
||||
mustContain: [
|
||||
'loadPlatformPlans',
|
||||
'createPlatformSubscription',
|
||||
'loadPlatformInvoices',
|
||||
'createPlatformInvoiceFromSubscription',
|
||||
'loadPlatformSubscriptionInvoiceCandidates',
|
||||
'createPlatformInvoicesBatchFromSubscriptions',
|
||||
'loadPlatformUsageOverageInvoiceCandidates',
|
||||
'createPlatformInvoicesFromUsageOverage',
|
||||
'confirmPlatformInvoicePayment',
|
||||
'loadPlatformUsage',
|
||||
'recordPlatformUsage',
|
||||
'processPlatformOverdueInvoices',
|
||||
'loadPlatformInvoiceReminders',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform.public-bank-grants',
|
||||
file: 'pages/platform-admin/question-banks/index.tsx',
|
||||
mustContain: [
|
||||
'loadPlatformQuestionBanks',
|
||||
'loadPlatformQuestionBankGrants',
|
||||
'upsertPlatformQuestionBankGrant',
|
||||
'allowedPlanCodes',
|
||||
'allowedTenantIds',
|
||||
'all_active_tenants',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform.staff-permissions',
|
||||
file: 'pages/platform-admin/staff/index.tsx',
|
||||
mustContain: [
|
||||
'loadPlatformPermissions',
|
||||
'loadPlatformStaff',
|
||||
'upsertPlatformStaff',
|
||||
'updatePlatformStaffStatus',
|
||||
'authUserId',
|
||||
'platformPermissions',
|
||||
'revokeSessions',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const routeContracts = [
|
||||
{
|
||||
id: 'student-first-web-launch',
|
||||
routes: [
|
||||
'pages/student/home/index',
|
||||
'pages/student/catalog/index',
|
||||
'pages/student/practice/index',
|
||||
'pages/student/review/index',
|
||||
'pages/student/checkout/index',
|
||||
'pages/student/order-detail/index',
|
||||
'pages/student/profile/index',
|
||||
'pages/student/notifications/index',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tenant-admin-launch',
|
||||
routes: [
|
||||
'pages/tenant-admin/workbench/index',
|
||||
'pages/tenant-admin/dashboard/index',
|
||||
'pages/tenant-admin/students/index',
|
||||
'pages/tenant-admin/content/index',
|
||||
'pages/tenant-admin/marketing/index',
|
||||
'pages/tenant-admin/finance/index',
|
||||
'pages/tenant-admin/settings/index',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'platform-admin-launch',
|
||||
routes: [
|
||||
'pages/platform-admin/workbench/index',
|
||||
'pages/platform-admin/tenants/index',
|
||||
'pages/platform-admin/billing/index',
|
||||
'pages/platform-admin/question-banks/index',
|
||||
'pages/platform-admin/staff/index',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function readText(relativePath) {
|
||||
return fs.readFileSync(path.join(taroSrc, relativePath), 'utf8').replace(/\r\n/g, '\n');
|
||||
}
|
||||
|
||||
function assertContains(text, token, label) {
|
||||
assert.ok(text.includes(token), `${label} must contain ${token}`);
|
||||
}
|
||||
|
||||
function assertNotContains(text, token, label) {
|
||||
assert.ok(!text.includes(token), `${label} must not contain ${token}`);
|
||||
}
|
||||
|
||||
function parseAppRoutes() {
|
||||
const text = readText('app.config.ts');
|
||||
const match = text.match(/pages\s*:\s*\[([\s\S]*?)\]/m);
|
||||
assert.ok(match, 'apps/taro/src/app.config.ts must define pages');
|
||||
return new Set([...match[1].matchAll(/['"`]([^'"`]+)['"`]/g)].map(item => item[1]));
|
||||
}
|
||||
|
||||
const appRoutes = parseAppRoutes();
|
||||
for (const contract of routeContracts) {
|
||||
for (const route of contract.routes) {
|
||||
assert.ok(appRoutes.has(route), `${contract.id} route must be registered: ${route}`);
|
||||
assert.ok(fs.existsSync(path.join(taroSrc, `${route}.tsx`)), `${contract.id} route file must exist: ${route}.tsx`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const contract of contracts) {
|
||||
const text = readText(contract.file);
|
||||
for (const token of contract.mustContain || []) assertContains(text, token, contract.id);
|
||||
for (const token of contract.mustNotContain || []) assertNotContains(text, token, contract.id);
|
||||
}
|
||||
|
||||
console.log(`[PASS] Taro persona contract (${contracts.length} page contracts, ${routeContracts.length} route groups)`);
|
||||
Reference in New Issue
Block a user