Files
MahdiandCursor 60d797f184 feat: باشگاه امتیازات کارکنان (موتور امتیاز، جدول رتبه، فروشگاه پاداش، نشان‌ها، پنل مدیریت و گزارش ROI)
- موتور رویدادمحور با شرط، محدودیت، تأیید مدیر و idempotency
- اتصال به لید، مشتری، معامله، فعالیت، روتین، پیش‌فاکتور، فاکتور و تیکت
- صفحه /club و /club/admin، اعلان زنده امتیاز، آیتم منو
- انتقال فرم‌ساز سرنخ به ابزارها

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 21:28:49 +03:30

88 lines
4.1 KiB
TypeScript

import { test, expect, waitForIdle } from './fixtures';
/** فقط خواندنی: هیچ رکوردی ساخته، ویرایش یا حذف نمی‌شود؛ اجرا روی سرور اصلی بی‌خطر است */
const PAGES: Array<[string, string]> = [
['/', 'داشبورد'],
['/contacts', 'مشتریان'],
['/leads', 'لیدها'],
['/pipeline', 'فروش'],
['/activities', 'کارها'],
['/activities/calendar', 'تقویم کارها'],
['/routines', 'کارهای روتین'],
['/conversations', 'گفتگو'],
['/notes', 'یادداشت‌ها'],
['/tickets', 'پشتیبانی'],
['/loyalty', 'باشگاه مشتریان'],
['/club', 'باشگاه امتیازات'],
['/reports', 'گزارش‌ها'],
['/invoices', 'فاکتورها'],
['/quotes', 'پیش‌فاکتورها'],
['/cheques', 'چک‌ها'],
['/projects', 'پروژه‌ها'],
['/profile', 'پروفایل'],
['/settings/team', 'تنظیمات تیم'],
['/settings/lead-forms', 'فرم‌های لید'],
['/settings/message-automations', 'اتوماسیون پیام'],
['/settings/tahesab', 'تنظیمات ته‌حساب'],
];
for (const [path, title] of PAGES) {
test(`صفحهٔ ${title} بدون خطا باز می‌شود (${path})`, async ({ page, problems }) => {
await page.goto(path);
await expect(page).not.toHaveURL(/\/login/);
await expect(page.locator('main.content')).toBeVisible();
await waitForIdle(page);
expect(problems.list).toEqual([]);
});
}
test('جستجوی سراسری باز می‌شود و نتیجه می‌دهد', async ({ page }) => {
await page.goto('/');
const search = page.getByPlaceholder(/جستجو در مشتریان/);
await expect(search).toBeVisible();
await search.fill('a');
await waitForIdle(page);
});
test('دارایی‌ها و اسناد ته‌حساب مشتری', async ({ page }) => {
const personId = process.env.E2E_PERSON_ID;
test.skip(!personId, 'E2E_PERSON_ID تنظیم نشده');
await page.goto(`/contacts/people/${personId}?tab=assets`);
await expect(page.getByRole('heading', { name: /مانده حساب/ })).toBeVisible({ timeout: 30_000 });
await page.getByRole('button', { name: 'جزئیات حساب', exact: true }).click();
await expect(page.locator('.invoice, .asnad-grid .sanad-card').first().or(page.getByText('در این بازه سندی یافت نشد'))).toBeVisible({ timeout: 60_000 });
const invoice = page.locator('.invoice').first();
if (await invoice.isVisible()) {
await expect(invoice.locator('.inv-head')).toContainText('سند شماره');
await expect(invoice.locator('.inv-table tbody tr').first()).toBeVisible();
}
});
async function findActiveFormToken(page: import('@playwright/test').Page) {
const listRes = page.waitForResponse((r) => /\/api\/lead-forms(\?|$)/.test(r.url()) && r.request().method() === 'GET');
await page.goto('/settings/lead-forms');
const forms = (await (await listRes).json()) as Array<{ publicToken: string; isActive: boolean }>;
return forms.find((f) => f.isActive)?.publicToken;
}
test('فرم عمومی لید بدون لاگین باز می‌شود', async ({ browser, page: adminPage }) => {
const token = await findActiveFormToken(adminPage);
test.skip(!token, 'هیچ فرم لید فعالی وجود ندارد');
const ctx = await browser.newContext({ storageState: undefined });
const page = await ctx.newPage();
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
await page.route('**/api/public/forms/*/event', (route) => route.fulfill({ status: 204 }));
const formRes = page.waitForResponse((r) => r.url().endsWith(`/api/public/forms/${token}`));
await page.goto(`/f/${token}`);
const status = (await formRes).status();
expect(
status,
'فرم فعالی که در پنل دیده می‌شود از لینک عمومی باز نشد',
).toBe(200);
await expect(page.locator('form')).toBeVisible();
await expect(page.getByRole('button', { name: /ارسال|ثبت/ })).toBeVisible();
expect(errors).toEqual([]);
await ctx.close();
});