feat: add QA driver for ClinicPro to automate testing and reporting

This commit is contained in:
hamed
2026-07-19 12:43:18 +03:30
parent fe2783480e
commit 0d9784b03a
2 changed files with 721 additions and 0 deletions
+300
View File
@@ -0,0 +1,300 @@
---
name: qa-clinicpro
description: تست QA اپلیکیشن ClinicPro مثل یک کاربر واقعی — اجرای اپ، ورود با هر نقش، پیمایش صفحات پنل ادمین، اسکرین‌شات، کشف خطاهای کنسول و شبکه، تست 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/` هستند.
## پیش‌نیازها
هیچ نصبی لازم نیست. فقط این دو:
```bash
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` هم که آن فایل ارجاع می‌دهد در ریپو نیستند.
نقش‌های واقعیِ کارکننده در `ROLES` داخل درایور هاردکد شده‌اند:
| نقش | موبایل | پسورد |
|---|---|---|
| `admin` | `09120671756` | `QaTest@1234` |
| `clinic` | `09127000000` | `QaTest@1234` |
| `secretary` | `09123456778` | `QaTest@1234` |
| `doctor` | `09390039833` | `09390039833` |
| `representation` | `09124000001` | `09124000001` |
سه تای اول پسوردشان عمداً برای QA ست شده. اگر DB ریست شد، دوباره ست کن:
```bash
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');"
```
اعتبارسنجی همه نقش‌ها:
```bash
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)
### ۱. بازدید از صفحه — اسکرین‌شات + خطاها
```bash
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 و پرجدول است و بیشتر مشکلات آنجاست:
```bash
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
```bash
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)
همان درخواست با همه نقش‌ها + ناشناس:
```bash
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` هم ۲۰۰ گرفت، درایور
هشدار می‌دهد.
### ۴. تست قرارداد API
```bash
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"}'`.
### ۵. کارایی
```bash
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 فعال شد، مثل یک **مهندس ارشد تست** رفتار کن، نه فقط اجراکننده دستور:
1. **اول سناریوی واقعی کاربر را بنویس**، بعد اجرا کن. مثال: ورود منشی → لیست نوبت‌ها →
تغییر وضعیت یک نوبت → خروج → ورود مجدد → آیا تغییر ماند؟
2. برای هر بخش این حالت‌ها را پوشش بده:
Happy Path · ورودی نامعتبر · داده خالی · داده خیلی زیاد (لیست ۱۰٬۹۳۲ کاربری) ·
شرایط مرزی · خطای شبکه · هر پنج نقش · دسکتاپ ۱۴۴۰ و موبایل ۳۹۰.
3. **هیچ چیز را حدس نزن.** ادعای بدون خروجی دستور، ادعا نیست.
4. **قبل از گزارش، باگ را دوباره تکرار کن.** همان دستور را دوباره بزن؛ اگر تکرار نشد،
flaky بودنش را بنویس نه خودِ باگ را.
5. باگ‌های کوچک UI را هم گزارش کن، ولی باگ‌های Business Logic اولویت بالاترند.
### فرمت Bug Report
هر یافته را با این قالب بنویس (فارسی):
```markdown
## 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 خواهر استفاده کن:
```bash
node .claude/skills/redesign-page/driver.mjs inspect "https://clinic-pro.ddev.site/admin/doctors"
```
### گزارش نهایی
۱. خلاصه وضعیت کلی · ۲. تعداد باگ‌ها · ۳. لیست بر اساس Severity ·
۴. باگ‌هایی که باید فوری رفع شوند · ۵. پیشنهاد بهبود کیفیت.
---
## 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` /
`localhost` `NODE_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` |
## باگ‌های شناخته‌شده (در همین اجرا پیدا شدند)
نمونه‌هایی از خروجی واقعی همین درایور، به‌عنوان مرجعِ اینکه گزارش چطور باشد:
1. **Medium** — در «وضعیت نوبت‌ها»ی داشبورد، برچسب‌های `confirmed` و `expired` انگلیسی
مانده‌اند در حالی که بقیه فارسی‌اند («تکمیل شده»، «لغو پزشک»).
بازتولید: `visit https://clinic-pro.ddev.site/admin/dashboard --as admin`، اسکرین‌شات.
2. **Low** — کارت «درآمد این ماه» کلمهٔ «تومان» را دو بار نشان می‌دهد (یک‌بار کنار عدد،
یک‌بار به‌عنوان زیرنویس کارت). همان اسکرین‌شات.
3. **Low** — در ویوپورت ۳۹۰px داشبورد، ۵ تارگت لمسی زیر ۳۶px هستند.
بازتولید: `ux … --w 390 --h 844`.
4. **Medium (مستندات)**`TEST_USERS.md` و بخش Category در `CLAUDE.md` هر دو منسوخ‌اند.