feat: add QA driver for ClinicPro to automate testing and reporting
This commit is contained in:
@@ -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` هر دو منسوخاند.
|
||||
Reference in New Issue
Block a user