fix(test): pricing script declared success after doing nothing

عطلان في سكربت التسعير، كشفهما أول تشغيل حقيقي:

1. **إعلان نجاح على العدم** — الأخطر. فشل تسجيل الدخول فجُمع صفر صفّ، فمرّ
   كل تحقّق فراغاً وطبع «الاختبار ناجح». اختبار يعلن النجاح وهو لم ينفّذ
   شيئاً أسوأ من اختبار يفشل: الفشل يُرى. أُضيف حارس عدم + تحقّق تغطية
   (المنفَّذ مقابل المتوقَّع)، وكلاهما يُخرج برمز فشل.

2. **تسجيل الدخول تجاوز `send-otp`** — تجاوز التطوير في `verifyOtp` مشروط
   بـ`OTP_DEV_MODE=true`، وبدونه لا رمز في Redis فيُرفض الثابت 1234 بـ401.
   صار يمرّ بـ`send-otp` ويأخذ `dev_code` من استجابتها، ويقول صراحةً حين
   يكون الوضع التطويري مطفأً بدل أن يفشل بلا تفسير.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-19 00:54:13 +03:00
co-authored by Claude Opus 4.8
parent 900c78bb97
commit 7501b0bb33
+36 -8
View File
@@ -114,9 +114,23 @@ function testPhone(countryPack, seed) {
async function loginRider(tenantSlug, countryPack, seed) { async function loginRider(tenantSlug, countryPack, seed) {
const phone = testPhone(countryPack, seed); const phone = testPhone(countryPack, seed);
// وضع OTP التطويري: رمز ثابت 1234 يُنشئ الحساب ويسجّل الدخول بنداء واحد
// (بلا حاجة لـ/auth/send-otp أولاً) — نفس نمط e2e-test.mjs. // **يجب** المرور بـ`send-otp` أولاً: تجاوز التطوير في `verifyOtp` مشروط
const r = await api('POST', '/auth/verify-otp', { tenant: tenantSlug, body: { phone, code: CODE } }); // بـ`OTP_DEV_MODE=true`، وبدونه لا يوجد رمز في Redis أصلاً فيُرفض أي رمز
// نرسله. النسخة الأولى نادت `verify-otp` مباشرةً بالرمز الثابت 1234
// فسقطت بـ401 على سيرفر وضعه التطويري مطفأ — وهو الوضع الصحيح لسيرفر حي.
const sent = await api('POST', '/auth/send-otp', { tenant: tenantSlug, body: { phone } });
const code = sent.body?.dev_code ?? CODE;
if (!sent.body?.dev_code) {
console.error(
` ⚠️ لا يوجد dev_code في استجابة send-otp — يعني OTP_DEV_MODE مطفأ.\n` +
` هذا السكربت يحتاجه لتسجيل دخول راكب اختبار. فعّله مؤقتاً في .env ثم` +
` أعد تشغيل الـapi، وأطفئه بعد الانتهاء.`,
);
}
const r = await api('POST', '/auth/verify-otp', { tenant: tenantSlug, body: { phone, code } });
if (!r.body?.access_token) { if (!r.body?.access_token) {
console.error(` ❌ فشل تسجيل الدخول (${phone}): ${r.status} ${JSON.stringify(r.body)}`); console.error(` ❌ فشل تسجيل الدخول (${phone}): ${r.status} ${JSON.stringify(r.body)}`);
} }
@@ -178,6 +192,20 @@ async function main() {
} }
console.log('\n=== النتائج ===\n'); console.log('\n=== النتائج ===\n');
// **حارس العدم**: النسخة الأولى طبعت «الاختبار ناجح» بعد أن فشل تسجيل
// الدخول وجُمع صفر صفّ — لأن كل تحقّق كان على مجموعة فارغة فمرّ فراغاً.
// اختبار يعلن النجاح وهو لم ينفّذ شيئاً أسوأ من اختبار يفشل: الفشل يُرى.
const expected = TENANTS.length * RIDES.length * SERVICE_CLASSES.length;
if (rows.length === 0) {
console.error('❌ لم يُنفَّذ ولا طلب واحد — لا نتيجة تُقرأ. راجع أخطاء تسجيل الدخول أعلاه.');
process.exitCode = 1;
return;
}
if (rows.length < expected) {
console.error(`⚠️ نُفِّذ ${rows.length} من ${expected} طلباً — التغطية ناقصة.`);
}
const noQuote = rows.filter((r) => !r.tariffFound); const noQuote = rows.filter((r) => !r.tariffFound);
if (noQuote.length) { if (noQuote.length) {
console.error(`❌ ${noQuote.length} طلب بلا سعر (تعرفة مفقودة) — هذا هو العطل الذي أصلحناه، فوجوده الآن خطأ حرج:`); console.error(`❌ ${noQuote.length} طلب بلا سعر (تعرفة مفقودة) — هذا هو العطل الذي أصلحناه، فوجوده الآن خطأ حرج:`);
@@ -218,13 +246,13 @@ async function main() {
} }
if (orderOk) console.log('✅ الفان أغلى من الاقتصادي في كل رحلة وكل بلد.'); if (orderOk) console.log('✅ الفان أغلى من الاقتصادي في كل رحلة وكل بلد.');
console.log(failedExitCode(noQuote.length, orderOk)); // المقارنة تحتاج الفئتين معاً؛ غيابهما يعني تحقّقاً لم يقع لا تحقّقاً نجح.
} const comparable = rows.filter((r) => ['economy', 'van'].includes(r.serviceClass)).length;
if (comparable === 0) console.error('⚠️ لا بيانات كافية للمقارنة — التحقّق أعلاه لم يقع فعلياً.');
function failedExitCode(missing, orderOk) { const bad = noQuote.length > 0 || !orderOk || rows.length < expected;
const bad = missing > 0 || !orderOk;
process.exitCode = bad ? 1 : 0; process.exitCode = bad ? 1 : 0;
return bad ? '\n❌ فشل الاختبار.' : '\n✅ الاختبار ناجح.'; console.log(bad ? '\n❌ فشل الاختبار.' : `\n✅ الاختبار ناجح (${rows.length} طلباً).`);
} }
main().catch((e) => { main().catch((e) => {