29 KiB
name, description
| name | description |
|---|---|
| qa-clinicpro | تست QA اپلیکیشن ClinicPro مثل یک کاربر واقعی — ابتدا ساخت همهٔ نقشها و پروفایلهای کامل (پزشک مستقل، پزشک عضو کلینیک، کلینیک، منشی، نماینده، بیمار، …) و تعیین ماتریس سطح دسترسی، سپس تست ماتریس دسترسی با تکتک آنها. هر مانعی سر راه تست را مثل یک دولوپر ارشد Symfony/React خودش رفع میکند و تست را ادامه میدهد. اجرای اپ، ورود با هر نقش، پیمایش صفحات پنل ادمین، اسکرینشات، کشف خطاهای کنسول و شبکه، تست UI/UX و RTL، تست دسترسی نقشها (authz)، تست قرارداد API و اندازهگیری کارایی، و تولید Bug Report. Use when asked to QA, test, smoke-test, find bugs in, screenshot, or verify ClinicPro's admin panel or API — «تست کن»، «باگ پیدا کن»، «QA کن»، «این صفحه را بررسی کن». |
QA ClinicPro
ClinicPro = بکاند Symfony 7.4 + یک SPA کلاینتساید React 19 که از /admin/* سرو میشود.
یعنی curl و فلگ --screenshot کروم به درد نمیخورند — هر دو روی فرم لاگین مینشینند،
چون JWT در localStorage['clinicpro-auth'] است.
درایور این skill آن کار را انجام میدهد: با API لاگین میکند، localStorage را seed
میکند، بعد ناوبری میکند و خطاهای کنسول، درخواستهای شکستخورده، مسیری که واقعاً روی آن
فرود آمده، و اسکرینشات را گزارش میدهد — با CDP روی WebSocket نیتیو Node 22،
بدون هیچ وابستگی npm (نه playwright، نه puppeteer).
مسیرها نسبت به clinicpro/ هستند.
پیشنیازها
هیچ نصبی لازم نیست. فقط این دو:
ddev describe | head -3 # باید بالا باشد: https://clinic-pro.ddev.site
ls "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
کروم جای دیگری است؟ CHROME_BIN را ست کن. بکاند جای دیگری است؟ CLINICPRO_BASE.
کاربران تست
⚠ TEST_USERS.md منسوخ است — هیچکدام از کاربرانش (09100000001, 09100100000, …)
در دیتابیس وجود ندارند و همه ERR_AUTH_005 میگیرند. اسکریپتهای create_test_users.php
و seed_realistic_data.php هم که آن فایل ارجاع میدهد در ریپو نیستند.
پرسوناهای QA در ROLES داخل درایور تعریف شدهاند. واحد کار «پرسونا» است، نه
ROLE_* — پزشک مستقل و پزشک عضو کلینیک هر دو ROLE_DOCTOR دارند ولی دادهٔ متفاوتی
میبینند، پس هرکدام یک ردیف جداگانهاند.
| پرسونا | موبایل | پسورد | نقشها | تمایز |
|---|---|---|---|---|
admin |
09120671756 |
QaTest@1234 |
ROLE_ADMIN |
— |
clinic |
09127000000 |
QaTest@1234 |
ROLE_CLINIC |
مالک کلینیک |
secretary |
09123456778 |
QaTest@1234 |
ROLE_SECRETARY |
منشیِ یک پزشک |
doctor |
09390039833 |
09390039833 |
ROLE_DOCTOR |
حساب قدیمی، وضعیت عضویتش نامعلوم |
representation |
09124000001 |
09124000001 |
ROLE_REPRESENTATION |
نماینده شهر |
doctor_solo |
09129000001 |
QaTest@1234 |
ROLE_DOCTOR |
پزشک مستقل — مطب شخصی، بدون کلینیک |
doctor_member |
09129000002 |
QaTest@1234 |
ROLE_DOCTOR |
پزشک عضو کلینیک |
clinic_doctor |
09129000003 |
QaTest@1234 |
ROLE_CLINIC+ROLE_DOCTOR |
چندنقشی |
secretary_clinic |
09129000004 |
QaTest@1234 |
ROLE_SECRETARY |
منشیِ کلینیک (نه پزشک) |
unclaimed_doctor |
09129000005 |
QaTest@1234 |
ROLE_UNCLAIMED_DOCTOR |
پروفایل ایمپورتشدهٔ تصاحبنشده |
patient |
09129000006 |
QaTest@1234 |
ROLE_USER |
کاربر عادی سایت |
importer |
09129000007 |
QaTest@1234 |
ROLE_IMPORTER |
— |
پنج ردیف اول موجودند. هفت ردیف آخر تا وقتی Phase 0 اجرا نشده وجود ندارند و
driver.mjs roles برایشان ✗ میدهد — این دقیقاً چک آمادگی است.
اگر DB ریست شد، پسورد پنجتای اول را دوباره ست کن:
ddev exec php bin/console security:hash-password 'QaTest@1234'
# هش خروجی را در این کوئری بگذار:
ddev mysql -e "UPDATE users SET password_hash='<هش>' \
WHERE mobile_number IN ('09120671756','09127000000','09123456778');"
اعتبارسنجی همه نقشها:
node .claude/skills/qa-clinicpro/driver.mjs roles
خروجی واقعی:
admin 09120671756 ROLE_USER,ROLE_ADMIN token 15min
clinic 09127000000 ROLE_USER,ROLE_CLINIC token 15min
secretary 09123456778 ROLE_USER,ROLE_SECRETARY token 15min
doctor 09390039833 ROLE_USER,ROLE_DOCTOR token 15min
representation 09124000001 ROLE_USER,ROLE_REPRESENTATION token 15min
میتوانی بهجای نام نقش، --as "0912xxxxxxx:password" هم بدهی.
مسیر اجرا (agent path)
۰. Phase 0 — ساخت نقشها، پروفایلها و ماتریس دسترسی (اجباری، قبل از هر تست)
هیچ تستی را قبل از تمامشدن این فاز شروع نکن. خروجی این فاز سه چیز است: همهٔ پرسوناها موجود · پروفایل هرکدام کامل · ماتریس دسترسی مکتوب.
۰.۱ — کشف نقشها. لیست بالا را دوباره از روی کد بساز، به آن استناد نکن؛ ممکن است نقشی اضافه شده باشد:
grep -rhoE "ROLE_[A-Z_]+" src/ assets/admin/ config/ | sort -u
ddev mysql -e "SELECT roles, COUNT(*) c FROM users GROUP BY roles ORDER BY c DESC;"
grep -n "role_hierarchy" -A 10 config/packages/security.yaml
هر نقشی که در کد هست و در جدول پرسوناها نیست را به ROLES در driver.mjs اضافه کن.
۰.۲ — چک آمادگی. ببین کدام پرسونا هنوز نیست:
node .claude/skills/qa-clinicpro/driver.mjs roles
۰.۳ — ساخت پرسوناهای ناموجود. برای هرکدام، اول مسیر واقعی ساخت را در خود اپ پیدا کن و از همان استفاده کن — دستکاری مستقیم SQL پروفایل ناقص میسازد و تست را دروغین میکند. به این ترتیب بگرد:
ls src/*/Command/ # آیا کامند کنسولی برای ساخت کاربر هست؟
grep -rn "IsGranted" src/Admin/Controller/ # اندپوینتهای ادمینِ ساخت کاربر
sed -n '1,80p' docs/api/admin.md
فقط برای چیزی که هیچ مسیر اپلیکیشنی ندارد (مثلاً ستکردن ROLE_IMPORTER یا ساختن
ROLE_UNCLAIMED_DOCTOR) به ddev mysql برگرد، و در گزارش بنویس که کدام پرسونا
دستی ساخته شد.
ترتیب ساخت مهم است — وابستگی دارند:
کلینیک → doctor_member (عضو همان کلینیک) → secretary_clinic (منشیِ همان کلینیک)
پزشک → secretary (منشیِ همان پزشک)
۰.۴ — کاملکردن پروفایل. یک حسابِ بدون پروفایل، صفحات را خالی نشان میدهد و باگهای واقعی را پنهان میکند. برای هر پرسونا اینها باید پر باشند:
| پرسونا | حداقل پروفایل لازم |
|---|---|
doctor_solo / doctor_member / clinic_doctor |
نام، تخصص، آدرس مطب، برنامهٔ کاری هفتگی، حداقل یک خدمت با تعرفه، حداقل یک بیمه |
clinic |
نام کلینیک، شهر، آدرس، حداقل یک پزشک عضو، حداقل یک خدمت |
secretary / secretary_clinic |
اتصال به پزشک/کلینیک + سطح دسترسیاش |
representation |
شهر تخصیصیافته |
patient |
نام، و حداقل یک نوبت رزروشده (برای اینکه صفحات خالی نباشند) |
unclaimed_doctor |
پروفایل پزشک بدون کاربرِ تصاحبکننده |
بعد از ساخت، پرشدن را تأیید کن — نه با حدس، با درخواست:
node .claude/skills/qa-clinicpro/driver.mjs api GET /api/v1/doctor/profile --as doctor_solo
۰.۵ — تعیین سطح دسترسی. ماتریس را از کد دربیاور، نه از ذهنت:
grep -n "RoleRoute\|allowedRoles\|element=" assets/admin/App.tsx # مسیرهای فرانت
grep -rn "IsGranted" src/*/Controller/ | sed 's/.*IsGranted(//' # گاردهای بکاند
از این دو، جدول مسیر → نقشهای مجاز را بساز و در گزارش بیاور. بعد برای هر اندپوینت
حساس با authz (بخش ۳) تأییدش کن. اختلاف بین ماتریسِ کد و خروجی authz = باگ،
حتی اگر خروجی authz سختگیرانهتر باشد.
۰.۶ — دروازهٔ خروج. تا وقتی roles برای همهٔ پرسوناها توکن برمیگرداند و ماتریس
نوشته شده، به فاز بعد نرو. اگر پرسونایی ساخته نشد، طبق بخش «وقتی به مانع خوردی»
خودت رفعش کن؛ رها کردنش یعنی آن نقش اصلاً تست نشده.
۱. بازدید از صفحه — اسکرینشات + خطاها
node .claude/skills/qa-clinicpro/driver.mjs visit \
"https://clinic-pro.ddev.site/admin/dashboard" --as admin --out /tmp/qa-dash.png
✓ screenshot /tmp/qa-dash.png (1440x900, as admin)
LANDING
(none)
CONSOLE ERRORS
(none)
NETWORK FAILURES
(none)
بعد حتماً تصویر را با ابزار Read باز کن و نگاه کن. نیمی از باگهای UI فقط دیدنیاند، نه لاگشدنی — همان یک اسکرینشات داشبورد دو باگ i18n لو داد (پایین را ببین).
فلگها: --w 1440 --h 900 (ویوپورت)، --wait 4000 (ms صبر برای رندر)، --full (کل صفحه).
موبایل را جدا تست کن — پنل RTL و پرجدول است و بیشتر مشکلات آنجاست:
node .claude/skills/qa-clinicpro/driver.mjs visit \
"https://clinic-pro.ddev.site/admin/dashboard" --as admin --w 390 --h 844 --out /tmp/qa-m.png
بخش LANDING دو حالتی را میگیرد که اسکرینشات پنهان میکند:
⚠ WRONG PAGE: asked /admin/users, landed /admin/dashboard — role likely lacks access (RoleRoute in App.tsx)
۲. آدیت UI/UX و RTL
node .claude/skills/qa-clinicpro/driver.mjs ux \
"https://clinic-pro.ddev.site/admin/dashboard" --as admin --w 390 --h 844
UX FINDINGS (390x844, as admin)
5 tap target(s) under 36px on a mobile viewport
چکها: RTL نبودن ریشه، lang غلط، سرریز افقی، رقم لاتین داخل متن فارسی، تارگت لمسی
زیر ۳۶px، <img> بدون alt، فیلد بدون label، id تکراری، جدول خالی بدون empty-state،
و <select> نیتیو (استاندارد پروژه SearchableSelect است).
۳. تست دسترسی نقشها (Security)
همان درخواست با همه نقشها + ناشناس:
node .claude/skills/qa-clinicpro/driver.mjs authz GET /api/v1/admin/users
AUTHZ GET /api/v1/admin/users
anonymous 401
admin 200
clinic 403
secretary 403
doctor 403
representation 403
200 for: admin
هر ۲۰۰ غیرمنتظره در این جدول = یک باگ Critical. اگر anonymous هم ۲۰۰ گرفت، درایور
هشدار میدهد.
۳.۱ جاروی کامل ماتریس — اجباری، نه نمونهای
authz خودش همهٔ پرسوناها را میزند، پس تست دسترسی نباید روی چند اندپوینت منتخب
بماند. لیست اندپوینتها را از روتر بگیر و همه را جارو کن:
ddev exec php bin/console debug:router --format=json \
| node -e 'const r=JSON.parse(require("fs").readFileSync(0));
for (const [n,v] of Object.entries(r))
if (v.path.startsWith("/api/v1") && !v.path.includes("{"))
console.log(v.method.split("|")[0].replace("ANY","GET"), v.path);' \
| while read m p; do
node .claude/skills/qa-clinicpro/driver.mjs authz "$m" "$p"
done | tee /tmp/qa-authz-matrix.txt
روی این DB حدود ۱۶۸ مسیر بدون پارامتر برمیگردد و authz برای هر مسیر بهازای هر
پرسونا دوباره لاگین میکند (≈۲۲۰۰ درخواست) — چند دقیقه طول میکشد، پس در پسزمینه
اجرایش کن و بعد فایل را بخوان. دو تله در خواندن خروجی:
- ۴۲۲ روی مسیرهای POST طبیعی است (بدنه خالی فرستاده شده) و باگ نیست؛ چیزی که مهم است تمایز ۴۰۱/۴۰۳ از بقیه است. اگر نقشی بهجای ۴۰۳ یک ۴۲۲ گرفت، یعنی گارد بعد از اعتبارسنجی اجرا شده — همان هم یافته است.
- مسیرهای عمومی (لاگین، ثبتنام، لیست شهرها) قاعدتاً برای
anonymousهم ۲۰۰اند؛ اول باconfig/packages/security.yamlتطبیق بده، بعد ادعای نشت کن.
اندپوینتهای پارامتردار ({uuid}) از این حلقه میافتند — آنها را دستی و با
شناسهٔ متعلق به پرسونای دیگر بزن، چون همانجاست که IDOR پیدا میشود:
# uuid پزشکِ دیگری را به پرسونای doctor_solo بده — باید ۴۰۳/۴۰۴ بگیرد، نه ۲۰۰
node .claude/skills/qa-clinicpro/driver.mjs authz GET /api/v1/doctor/<uuid-of-another-doctor>
سه الگویی که باید در /tmp/qa-authz-matrix.txt دنبالشان بگردی:
| یافته | معنی |
|---|---|
anonymous = ۲۰۰ روی مسیر غیرعمومی |
نشت داده — Critical |
| نقشی ۲۰۰ میگیرد که در ماتریس ۰.۵ نبود | گارد جا افتاده — Critical |
| ۲۰۰ روی uuidِ مستأجر دیگر | IDOR — Critical |
| نقشی ۴۰۳ میگیرد که طبق ماتریس باید ۲۰۰ بگیرد | یا گارد سختگیر است یا ماتریس غلط — بررسی کن |
| ۵۰۰ بهجای ۴۰۳ | گارد کار میکند ولی خطا مدیریت نشده — High |
بدون این جدولِ کامل، فاز دسترسی تمامشده نیست. خروجیاش را در گزارش نهایی بیاور.
۴. تست قرارداد API
node .claude/skills/qa-clinicpro/driver.mjs api GET /api/v1/categorys/state --as admin
GET /api/v1/categorys/state → 301 12ms (as admin)
ENVELOPE
(none)
BODY
{
"success": false,
"data": null,
"errors": [
{ "code": "ERR_MOVED", "message": "این endpoint منتقل شده. لطفاً از /api/v1/provinces استفاده کنید." }
]
}
بخش ENVELOPE پاکت BaseController را چک میکند: نبودِ success، پاسخ خطای بدون
errors، و دام معروف double/triple nesting (data.data.data).
POST هم میشود: --body '{"name":"x"}'.
۵. کارایی
node .claude/skills/qa-clinicpro/driver.mjs perf "https://clinic-pro.ddev.site/admin/doctors" --as admin
PERF https://clinic-pro.ddev.site/admin/doctors (as admin)
ttfb 12ms
domContentLoaded 232ms
load 233ms
first-paint 180ms
first-contentful-paint 248ms
resources 24 · DOM nodes 1132
SLOWEST API CALLS
18ms 2kb v1/admin/doctors?page=1&limit=25
17ms 1kb v1/admin/doctors/stats
17ms 5kb v1/specialties
13ms 1kb v1/provinces
نقش QA و روش کار
وقتی این skill فعال شد، مثل یک مهندس ارشد تست رفتار کن، نه فقط اجراکننده دستور:
- Phase 0 را تمام کن (بالا). بدون پرسوناهای کامل، هر تستی نتیجهٔ بیمعنی میدهد.
- اول سناریوی واقعی کاربر را بنویس، بعد اجرا کن. مثال: ورود منشی → لیست نوبتها → تغییر وضعیت یک نوبت → خروج → ورود مجدد → آیا تغییر ماند؟
پیمایش با هر پرسونا اجباری است. بعد از Phase 0، برای هر پرسونا در جدول، وارد شو و
مسیرهای مجازش را طبق ماتریس ۰.۵ بگرد — نه فقط با admin. برای هر پرسونا حداقل:
for p in admin clinic doctor_solo doctor_member clinic_doctor \
secretary secretary_clinic representation patient; do
node .claude/skills/qa-clinicpro/driver.mjs visit \
"https://clinic-pro.ddev.site/admin/dashboard" --as "$p" --out "/tmp/qa-$p.png"
done
بعد هر اسکرینشات را با Read باز کن و ببین — و بخش LANDING را بخوان تا ریدایرکت
بیصدای نقش را نگیری. سه چیزی که فقط با مقایسهٔ بین پرسوناها پیدا میشوند:
- نشت داده بین مستأجرها: آیا
doctor_soloدادهٔ بیمار پزشک دیگری را میبیند؟ آیاclinicنوبتهای پزشک غیرعضو را میبیند؟ اینها همیشه Criticalاند. - صفحهٔ سفید بهجای «دسترسی ندارید»: نقشی که نباید ببیند، باید پیام روشن بگیرد.
- منوی سایدبار در برابر دسترسی واقعی: آیتمی که نمایش داده میشود ولی به ۴۰۳ میخورد (یا برعکس: مسیر باز است ولی در منو نیست) باگ است.
- برای هر بخش این حالتها را پوشش بده: Happy Path · ورودی نامعتبر · داده خالی · داده خیلی زیاد (لیست ۱۰٬۹۳۲ کاربری) · شرایط مرزی · خطای شبکه · همهٔ پرسوناها · دسکتاپ ۱۴۴۰ و موبایل ۳۹۰.
- هیچ چیز را حدس نزن. ادعای بدون خروجی دستور، ادعا نیست.
- قبل از گزارش، باگ را دوباره تکرار کن. همان دستور را دوباره بزن؛ اگر تکرار نشد، flaky بودنش را بنویس نه خودِ باگ را.
- باگهای کوچک UI را هم گزارش کن، ولی باگهای Business Logic اولویت بالاترند.
وقتی به مانع خوردی — رفعش کن، بعد برو تست بعدی
QA اینجا فقط گزارشنویس نیست. هر جا اجرای تست گیر کرد، مثل یک دولوپر ارشد Symfony/React خودت مشکل را حل کن، تأیید کن که حل شده، و تست را از همانجا ادامه بده. توقف روی اولین مانع یعنی بقیهٔ نقشها هیچوقت تست نمیشوند.
روال ثابت هر مانع:
بازتولید → ریشهیابی (نه علامت) → اصلاح → اثبات اصلاح → ثبت → ادامهٔ همان تست
- ریشه را پیدا کن، نه علامت را.
visitصفحهٔ سفید داد؟ اولCONSOLE ERRORSوNETWORK FAILURES، بعد فایل سورس صفحه (redesign-page/driver.mjs inspect)، بعد کنترلر مربوطه. اصلاح باید در همان لایهای باشد که علت آنجاست. - طبق قواعد پروژه اصلاح کن، نه با وصلهٔ سریع:
- بکاند:
extends BaseController، خطا باAppException(ErrorCodes::…)، کد SOLID، تغییر entity ⟵doctrine:migrations:diff+migrate. - فرانت: TanStack Query برای دادهٔ سرور، کامپوننتهای
components/ui/، توکنهایstyles.css(هیچ hex هاردکد)، رشتههای فارسی. - اندپوینت عوض شد ⟵ همان جلسه
docs/api/<domain>.mdرا بهروز کن (قاعدهٔ ثابت پروژه).
- بکاند:
- اثبات کن. همان دستوری که شکست خورده بود را دوباره بزن و خروجی سالمش را نشان بده.
بعد
ddev exec php bin/phpunitو در صورت تغییر فرانتnpx tsc --noEmitرا اجرا کن تا مطمئن شوی چیزی نشکستهای. - ثبت کن. هر اصلاح یک ورودی در بخش «Fixes Applied» گزارش نهایی میگیرد: مانع · ریشه · فایلهای تغییریافته · دستور اثبات.
مرزهایی که رد نمیکنی:
- باگ محصول را بیصدا رفع نکن. اگر مانع خودش یک باگ واقعی محصول است، هم Bug Report را بنویس هم اصلاح را — نه فقط اصلاح. گزارش، خروجی کار است.
- هرگز برای سبزشدن تست، دسترسی را باز نکن. اگر نقشی ۴۰۳ میگیرد و تو انتظار ۲۰۰
داری، پیشفرض این است که انتظارت غلط است.
IsGrantedیاRoleRouteرا فقط وقتی عوض کن که از روی کد ثابت کرده باشی آن نقش باید دسترسی داشته باشد، و دلیلش را بنویس. همین قاعده برای حذف اعتبارسنجی ورودی هم هست. - دادهٔ تست را با تغییر محصول نساز. کمبود دادهٔ پرسونا را با seed درست کن، نه با نرمکردن یک قاعدهٔ کسبوکار.
- مهاجرت مخرب نزن. روی DB لوکالِ پر (۱۰٬۹۳۲ کاربر)
doctrine:schema:dropیا مهاجرتی که ستون پرداده را میاندازد، ممنوع. - اگر اصلاح از تست بزرگتر شد (بازطراحی معماری، تغییر شکستدهندهٔ قرارداد API که
nobat724_frontوclinic-pro-tauriهم مصرفش میکنند)، دست نگه دار: باگ را با اصلاح پیشنهادی گزارش کن، آن یک تست راSKIPPEDعلامت بزن، و برو تست بعدی.
فرمت Bug Report
هر یافته را با این قالب بنویس (فارسی):
## Title
<عنوان کوتاه و مشخص>
- **Severity:** Critical | High | Medium | Low
- **Priority:** فوری | مهم | معمولی | کم
- **Environment:** Chrome headless · macOS · ddev · نقش: <role> · ویوپورت: <w>x<h>
### Description
### Steps To Reproduce
1. `node .claude/skills/qa-clinicpro/driver.mjs …` ← دستور دقیق، نه توضیح
2.
### Expected Behavior
### Actual Behavior
### Evidence
<خروجی درایور، مسیر اسکرینشات، پاسخ API>
### Impact
### Suggested Fix
<فایل:خط اگر پیدا کردی>
برای پیدا کردن فایل سورس یک صفحه از روی URL، از skill خواهر استفاده کن:
node .claude/skills/redesign-page/driver.mjs inspect "https://clinic-pro.ddev.site/admin/doctors"
گزارش نهایی
۱. خلاصه وضعیت کلی · ۲. تعداد باگها · ۳. لیست بر اساس Severity · ۴. باگهایی که باید فوری رفع شوند · ۵. پیشنهاد بهبود کیفیت.
بهعلاوه این سه بخش که از قواعد بالا میآیند:
۶. Fixes Applied — هر مانعی که خودت رفع کردی:
| مانع | ریشه | فایلهای تغییریافته | دستور اثبات |
|---|
۷. ماتریس دسترسی — جدول کامل مسیر × پرسونا از بخش ۳.۱، با اختلافهای
ماتریسِ کد و رفتار واقعی مشخصشده.
۸. پوشش — کدام پرسونا چه چیزی تست شد، و هر SKIPPED با دلیلش. اگر نقشی تست نشد
باید اینجا صریح بیاید؛ گزارشِ ساکت بدتر از گزارش ناقص است.
Gotchas
- SPA است، پس
curlصفحه نمیدهد.curl /admin/doctorsهمیشه همان HTML پوسته را برمیگرداند. هر ادعایی درباره محتوای صفحه باید ازvisitبیاید. - ریدایرکت بیصدای نقش.
RoleRouteدرApp.tsxکاربر بدون دسترسی را بیهیچ پیغامی به/dashboardمیفرستد — اسکرینشات کاملاً سالم بهنظر میرسد ولی صفحهٔ اشتباهی است. همیشه بخشLANDINGرا بخوان. - توکن فقط ۱۵ دقیقه اعتبار دارد. درایور برای هر دستور دوباره لاگین میکند، پس مسئلهای نیست؛ ولی اگر خودت توکن را جایی کش کردی، انتظار ۴۰۱ داشته باش.
TEST_USERS.mdدروغ میگوید (بالا). به آن استناد نکن.CLAUDE.mdهم روی/api/v1/categorys/{bundle}منسوخ است — آن مسیر حالا ۳۰۱ باERR_MOVEDمیدهد و مسیر واقعی/api/v1/provincesاست.- گواهی TLS ddev را Node قبول نمیکند. درایور فقط برای هاستهای
*.ddev.site/localhostNODE_TLS_REJECT_UNAUTHORIZED=0میگذارد و وارنینگ نویزیاش را خفه میکند. - خطاهای صفحهٔ لاگین به حساب صفحهٔ تحت تست نوشته نشوند. درایور بافر خطا را بعد از
seed کردن
localStorageو قبل از ناوبری به URL هدف پاک میکند. - دیتای لوکال واقعی و بزرگ است (۱۰٬۹۳۲ کاربر، ۲۰۲ کلینیک، ۱۷۹ پزشک) — برای تست «داده زیاد» لازم نیست چیزی seed کنی.
- CDP روی پورت ۹۴۴۴ است تا با درایور
redesign-page(پورت ۹۳۳۳) تداخل نکند؛ میتوانی هر دو را همزمان اجرا کنی.CDP_PORTقابل تغییر است.
Troubleshooting
| نشانه | علت / رفع |
|---|---|
login as admin failed: … ERR_AUTH_005 |
DB ریست شده؛ پسورد QA را دوباره ست کن (بخش «کاربران تست») |
Chrome did not expose CDP on :9444 |
CHROME_BIN غلط است، یا نمونهٔ قبلی کروم روی همان پورت مانده — pkill -f clinicpro-qa |
⚠ page text only N chars |
رندر SPA کرش کرده یا کند است؛ اول --wait 8000 را امتحان کن، بعد CONSOLE ERRORS را بخوان |
⚠ redirected to /login |
توکن رد شده — با driver.mjs login <role> صحتش را چک کن |
fetch failed / ECONNREFUSED |
ddev بالا نیست: ddev start |
باگهای شناختهشده (در همین اجرا پیدا شدند)
نمونههایی از خروجی واقعی همین درایور، بهعنوان مرجعِ اینکه گزارش چطور باشد:
- Medium — در «وضعیت نوبتها»ی داشبورد، برچسبهای
confirmedوexpiredانگلیسی ماندهاند در حالی که بقیه فارسیاند («تکمیل شده»، «لغو پزشک»). بازتولید:visit https://clinic-pro.ddev.site/admin/dashboard --as admin، اسکرینشات. - Low — کارت «درآمد این ماه» کلمهٔ «تومان» را دو بار نشان میدهد (یکبار کنار عدد، یکبار بهعنوان زیرنویس کارت). همان اسکرینشات.
- Low — در ویوپورت ۳۹۰px داشبورد، ۵ تارگت لمسی زیر ۳۶px هستند.
بازتولید:
ux … --w 390 --h 844. - Medium (مستندات) —
TEST_USERS.mdو بخش Category درCLAUDE.mdهر دو منسوخاند.