112 lines
5.5 KiB
JavaScript
112 lines
5.5 KiB
JavaScript
const test = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
|
|
const root = path.resolve(__dirname, '..', '..')
|
|
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8')
|
|
|
|
const templates = read('src/Settings/MailTemplates.php')
|
|
const mail = read('src/Settings/Mail.php')
|
|
const schemaProvider = read('src/Admin/SchemaProvider.php')
|
|
const notifications = read('src/Settings/MailNotifications.php')
|
|
const coreHooks = read('inc/core-hooks.php')
|
|
const globalController = read('src/Admin/GlobalController.php')
|
|
const userController = read('src/Admin/UserController.php')
|
|
const settings = read('src/Settings/Settings.php')
|
|
|
|
test('email catalog includes required non-forum and financial events', () => {
|
|
const required = [
|
|
'reg_verify_code', 'reg_success', 'login_code', 'password_reset', 'change_code', 'change_notice',
|
|
'order_paid', 'order_status', 'withdraw_submitted', 'withdraw_completed', 'affiliate_commission',
|
|
'creator_income', 'transfer_received', 'comment_approved', 'comment_reply', 'post_result',
|
|
'phone_changed', 'auth_apply_result', 'user_ban', 'report_result',
|
|
'order_paid_admin', 'withdraw_submitted_admin',
|
|
]
|
|
for (const event of required) {
|
|
assert.match(templates, new RegExp(`'${event}'\\s*=>\\s*self::event`), event)
|
|
}
|
|
})
|
|
|
|
test('forum-only events stay out of the email catalog', () => {
|
|
for (const forbidden of ['bbs', 'moderator', 'answer_adopted', 'answer-adopted']) {
|
|
assert.doesNotMatch(templates, new RegExp(forbidden, 'i'))
|
|
assert.doesNotMatch(notifications, new RegExp(forbidden, 'i'))
|
|
}
|
|
})
|
|
|
|
test('email settings keep one canonical SMTP schema', () => {
|
|
assert.match(templates, /'option_key'\s*=>\s*'aksrt_settings'/)
|
|
assert.match(templates, /'mail_passwd'.*'secret'\s*=>\s*true/)
|
|
assert.match(templates, /'email_test_send'.*'ui_only'\s*=>\s*true/)
|
|
assert.match(mail, /Settings::get_all\(\)/)
|
|
assert.match(mail, /'auth'\s*=>\s*\$username\s*!==\s*''\s*&&\s*\$password\s*!==\s*''/)
|
|
assert.doesNotMatch(templates, /mail_smtpauth/)
|
|
assert.doesNotMatch(mail, /mail_smtpauth/)
|
|
assert.doesNotMatch(settings, /aksrt_mail_smtp/)
|
|
assert.doesNotMatch(globalController, /aksrt_mail_config|\/settings\/mail'/)
|
|
assert.doesNotMatch(userController, /aksrt_mail_templates|mail-templates/)
|
|
})
|
|
|
|
test('email event schema exposes only notification switches', () => {
|
|
assert.match(templates, /private static function event_group\([^)]*\): array/)
|
|
assert.match(templates, /\$fields\[\] = \['key' => "email_\{\$event\}_enabled"/)
|
|
assert.doesNotMatch(templates, /email_\{\$event\}_subject/)
|
|
assert.doesNotMatch(templates, /email_\{\$event\}_content/)
|
|
assert.doesNotMatch(templates, /email_[A-Za-z0-9_]+_(subject|content)/)
|
|
assert.doesNotMatch(templates, /主题模板|正文模板|可用占位符/)
|
|
assert.doesNotMatch(schemaProvider, /is_mail_template|email_.+_\(subject\|content\)/)
|
|
})
|
|
|
|
test('mail runtime always uses the built-in event catalog', () => {
|
|
assert.match(mail, /replace_placeholders\(\(string\) \$definition\['title'\], \$placeholders\)/)
|
|
assert.match(mail, /replace_placeholders\(\(string\) \$definition\['content'\], \$placeholders\)/)
|
|
assert.doesNotMatch(mail, /\$subject_key|\$content_key|default_subject|default_content/)
|
|
assert.doesNotMatch(mail, /get_email_event_config\(\)/)
|
|
})
|
|
|
|
test('SMTP authentication and failures use the canonical mail service', () => {
|
|
assert.match(coreHooks, /add_filter\('wp_mail_from',/)
|
|
assert.match(coreHooks, /add_filter\('wp_mail_from_name',/)
|
|
assert.match(coreHooks, /if \(empty\(\$mail\['enabled'\]\)\) return \$from/)
|
|
assert.match(coreHooks, /if \(empty\(\$mail\['enabled'\]\)\) return \$from_name/)
|
|
assert.match(coreHooks, /\$mail\['from_address'\]/)
|
|
assert.match(coreHooks, /\$mail\['from_name'\]/)
|
|
assert.match(coreHooks, /\$phpmailer->SMTPAuth\s*=\s*!empty\(\$mail\['auth'\]\)\s*&&\s*!empty\(\$mail\['username'\]\)/)
|
|
assert.doesNotMatch(coreHooks, /\$phpmailer->setFrom\(/)
|
|
assert.match(mail, /add_action\('wp_mail_failed',\s*\$capture_failure\)/)
|
|
assert.match(mail, /remove_action\('wp_mail_failed',\s*\$capture_failure\)/)
|
|
assert.match(mail, /error_log\('\[AKSRT\] SMTP 测试失败:'/)
|
|
assert.match(globalController, /详细原因已写入服务器错误日志/)
|
|
})
|
|
|
|
test('canonical mail service contains no obsolete catalog or placeholder branches', () => {
|
|
assert.doesNotMatch(mail, /public static function events\s*\(/)
|
|
assert.doesNotMatch(mail, /replace_placeholders\([^\n]+,\s*false\)/)
|
|
assert.doesNotMatch(mail, /replace_placeholders\(string \$value, array \$placeholders, bool \$html\)/)
|
|
})
|
|
|
|
test('only the canonical mail service calls wp_mail', () => {
|
|
const phpFiles = []
|
|
const walk = (dir) => {
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, entry.name)
|
|
if (entry.isDirectory()) walk(full)
|
|
else if (entry.name.endsWith('.php')) phpFiles.push(full)
|
|
}
|
|
}
|
|
walk(root)
|
|
const callers = phpFiles.filter((file) => /wp_mail\s*\(/.test(fs.readFileSync(file, 'utf8')))
|
|
assert.deepEqual(callers.map((file) => path.relative(root, file).replaceAll('\\', '/')), ['src/Settings/Mail.php'])
|
|
})
|
|
|
|
test('financial and account hooks are wired to the notification service', () => {
|
|
for (const hook of [
|
|
'aksrt_order_paid', 'aksrt_order_status_changed', 'aksrt_asset_transaction_committed',
|
|
'aksrt_withdrawal_submitted', 'aksrt_withdrawal_status_changed',
|
|
'aksrt_user_phone_changed',
|
|
]) {
|
|
assert.match(notifications, new RegExp(`add_action\\('${hook}'`), hook)
|
|
}
|
|
})
|