207 lines
7.2 KiB
JavaScript
207 lines
7.2 KiB
JavaScript
import assert from 'node:assert';
|
|
import { resolveRevokeFeedback, resolveIssueFeedback, resolveReconcileFeedback } from '../../src/views/train/auth/authFeedback.js';
|
|
|
|
console.log('--- Testing resolveRevokeFeedback ---');
|
|
|
|
// 1. REVOKE: FAILED (decision == FAILED || success == false)
|
|
{
|
|
const res = resolveRevokeFeedback({ decision: 'FAILED', success: false, reason: '设备离线超时' });
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.message, '设备离线超时');
|
|
assert.strictEqual(res.message.includes('成功'), false);
|
|
}
|
|
{
|
|
const res = resolveRevokeFeedback({ decision: 'REVOKE_REQUIRED', success: false, reason: 'DMS rejected delete' });
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.message, 'DMS rejected delete');
|
|
assert.strictEqual(res.message.includes('成功'), false);
|
|
}
|
|
|
|
// 2. REVOKE: WAITING/queued (decision == REVOKE_REQUIRED && success=true && !externalInvoked)
|
|
{
|
|
const res = resolveRevokeFeedback({
|
|
decision: 'REVOKE_REQUIRED',
|
|
success: true,
|
|
externalInvoked: false,
|
|
reason: 'DMS disabled; authorization has externalAuthId 123, revoke queued as CREATED'
|
|
});
|
|
assert.strictEqual(res.type, 'warning');
|
|
assert.strictEqual(res.message.includes('当前未执行外部注销') || res.message.includes('queued'), true);
|
|
assert.strictEqual(res.message.includes('注销成功'), false);
|
|
}
|
|
|
|
// 3. REVOKE: IN_PROGRESS / Dispatched (decision == REVOKE_REQUIRED && success=true && externalInvoked=true)
|
|
{
|
|
const res = resolveRevokeFeedback({
|
|
decision: 'REVOKE_REQUIRED',
|
|
success: true,
|
|
externalInvoked: true,
|
|
reason: 'Password delete accepted by DMS; awaiting poller'
|
|
});
|
|
assert.strictEqual(res.type, 'info');
|
|
assert.strictEqual(res.message, '注销请求已提交,等待设备确认。');
|
|
}
|
|
|
|
// 4. REVOKE: NO_ACTION (decision == NO_ACTION && success=true)
|
|
{
|
|
const res = resolveRevokeFeedback({
|
|
decision: 'NO_ACTION',
|
|
success: true,
|
|
reason: 'Draft auth never issued to external system; marked REVOKED locally'
|
|
});
|
|
assert.strictEqual(res.type, 'info');
|
|
assert.strictEqual(res.message, 'Draft auth never issued to external system; marked REVOKED locally');
|
|
}
|
|
|
|
console.log('--- Testing resolveIssueFeedback ---');
|
|
|
|
// 1. ISSUE: ACCEPTED with credential
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'ACCEPTED',
|
|
message: '凭据已提交下发,设备确认后生效。',
|
|
oneTimePlaintextCredential: '829471'
|
|
});
|
|
assert.strictEqual(res.type, 'success');
|
|
assert.strictEqual(res.openCredentialDialog, true);
|
|
assert.strictEqual(res.message, '凭据已提交下发,设备确认后生效。');
|
|
}
|
|
|
|
// 2. ISSUE: ACCEPTED without credential
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'ACCEPTED',
|
|
message: '凭据已提交下发,设备确认后生效。',
|
|
oneTimePlaintextCredential: null
|
|
});
|
|
assert.strictEqual(res.type, 'success');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
}
|
|
|
|
// 3. ISSUE: WAITING_FOR_PREREQUISITE (MISSING_STUDENT_PHONE)
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'WAITING_FOR_PREREQUISITE',
|
|
message: 'MISSING_STUDENT_PHONE: 学员主档缺失有效手机号,暂无法下发门禁'
|
|
});
|
|
assert.strictEqual(res.type, 'warning');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
assert.strictEqual(res.message.includes('MISSING_STUDENT_PHONE'), true);
|
|
}
|
|
|
|
// 4. ISSUE: WAITING_FOR_PREREQUISITE (INVALID_VALIDITY_WINDOW)
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'WAITING_FOR_PREREQUISITE',
|
|
message: 'INVALID_VALIDITY_WINDOW: 培训计划结束时间缺失或早于生效开始时间,无法确定凭据有效期窗口'
|
|
});
|
|
assert.strictEqual(res.type, 'warning');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
assert.strictEqual(res.message.includes('INVALID_VALIDITY_WINDOW'), true);
|
|
}
|
|
|
|
// 5. ISSUE: WAITING_FOR_PREREQUISITE (DMS_DISABLED)
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'WAITING_FOR_PREREQUISITE',
|
|
message: 'DMS_DISABLED: 共享运行环境门禁对接未启用 (dms.enabled=false),无法向外部厂商下发门禁凭据'
|
|
});
|
|
assert.strictEqual(res.type, 'warning');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
assert.strictEqual(res.message.includes('DMS_DISABLED'), true);
|
|
}
|
|
|
|
// 6. ISSUE: AMBIGUOUS (AMBIGUOUS_EXTERNAL_MUTATION)
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'AMBIGUOUS_EXTERNAL_MUTATION',
|
|
message: 'AMBIGUOUS_EXTERNAL_MUTATION: 上一次下发结果无法确认,禁止重复下发,请先核对厂商侧凭据。(MANUAL_VENDOR_RECONCILIATION_REQUIRED)'
|
|
});
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
assert.strictEqual(res.message.includes('禁止重复下发'), true);
|
|
}
|
|
|
|
// 7. ISSUE: FAILED
|
|
{
|
|
const res = resolveIssueFeedback({
|
|
status: 'FAILED',
|
|
message: '门禁凭据下发失败 (厂商拒绝): 门锁离线'
|
|
});
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.openCredentialDialog, false);
|
|
assert.strictEqual(res.message.includes('门禁凭据下发失败'), true);
|
|
}
|
|
|
|
console.log('--- Testing resolveReconcileFeedback ---');
|
|
|
|
// 1. RECONCILE: ALL_SETTLED
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'ALL_SETTLED' },
|
|
success: true,
|
|
reason: 'All settled'
|
|
});
|
|
assert.strictEqual(res.type, 'success');
|
|
assert.strictEqual(res.message, 'All settled');
|
|
}
|
|
|
|
// 2. RECONCILE: IN_PROGRESS
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'IN_PROGRESS' },
|
|
success: true
|
|
});
|
|
assert.strictEqual(res.type, 'info');
|
|
assert.strictEqual(res.message.includes('指令已派发至外部设备'), true);
|
|
}
|
|
|
|
// 3. RECONCILE: WAITING_FOR_DMS
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'WAITING_FOR_DMS' },
|
|
success: true
|
|
});
|
|
assert.strictEqual(res.type, 'warning');
|
|
assert.strictEqual(res.message.includes('等待DMS恢复后处理'), true);
|
|
assert.strictEqual(res.message.includes('成功'), false);
|
|
}
|
|
|
|
// 4. RECONCILE: PARTIAL_FAILURE (必须为 error,严禁 success,严禁“对账执行成功”)
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'PARTIAL_FAILURE' },
|
|
success: false,
|
|
reason: '2 dispatched, 1 failed'
|
|
});
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.message.includes('部分处理失败'), true);
|
|
assert.strictEqual(res.message.includes('对账执行成功'), false);
|
|
}
|
|
|
|
// 5. RECONCILE: ALL_FAILED (必须为 error,严禁 success)
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'ALL_FAILED' },
|
|
success: false,
|
|
reason: 'All failed'
|
|
});
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.message.includes('对账处理失败') || res.message.includes('执行失败'), true);
|
|
assert.strictEqual(res.message.includes('对账执行成功'), false);
|
|
}
|
|
|
|
// 6. RECONCILE: REQUIRES_MANUAL_SETTLEMENT (必须为 error,明确需要人工核对厂商侧状态)
|
|
{
|
|
const res = resolveReconcileFeedback({
|
|
batchResult: { outcome: 'REQUIRES_MANUAL_SETTLEMENT' },
|
|
success: false,
|
|
reason: 'Manual check required'
|
|
});
|
|
assert.strictEqual(res.type, 'error');
|
|
assert.strictEqual(res.message.includes('需要人工核对厂商侧状态'), true);
|
|
assert.strictEqual(res.message.includes('对账执行成功'), false);
|
|
}
|
|
|
|
console.log('ALL FRONTEND FEEDBACK TESTS PASSED!');
|