169 خطوط
9.5 KiB
JavaScript
169 خطوط
9.5 KiB
JavaScript
import { expect, test } from '@playwright/test';
|
|
|
|
test('login password can be shown and hidden', async ({ page }) => {
|
|
await page.goto('/login');
|
|
const password = page.locator('#login-password');
|
|
await password.fill('secret-password');
|
|
await expect(password).toHaveAttribute('type', 'password');
|
|
await page.getByRole('button', { name: 'نمایش رمز عبور' }).click();
|
|
await expect(password).toHaveAttribute('type', 'text');
|
|
await page.getByRole('button', { name: 'مخفی کردن رمز عبور' }).click();
|
|
await expect(password).toHaveAttribute('type', 'password');
|
|
});
|
|
|
|
test('dashboard command surfaces and settings render without runtime errors', async ({ page }, testInfo) => {
|
|
const runtimeErrors = [];
|
|
page.on('pageerror', (error) => runtimeErrors.push(error.message));
|
|
page.on('console', (message) => {
|
|
if (message.type() === 'error') runtimeErrors.push(message.text());
|
|
});
|
|
|
|
const user = { id: 1, name: 'مدیر تست رابط', email: 'ui@example.test', permissions: ['reports.view', 'settings.view', 'notifications.view'] };
|
|
await page.addInitScript(({ testUser }) => {
|
|
localStorage.setItem('token', 'visual-smoke-token');
|
|
localStorage.setItem('user', JSON.stringify(testUser));
|
|
}, { testUser: user });
|
|
await page.route('**/api/**', async (route) => {
|
|
const url = new URL(route.request().url());
|
|
const path = url.pathname;
|
|
if (path === '/api/user') return route.fulfill({ json: { success: true, data: user } });
|
|
if (path === '/api/dashboard/monitoring') return route.fulfill({ json: { success: true, data: {
|
|
generated_at: new Date().toISOString(),
|
|
summary: { active_projects: 4, projects_at_risk: 1, open_tasks: 18, overdue_tasks: 3, blocked_tasks: 2, active_sprints: 2, meetings_today: 3, overdue_action_items: 1, open_blockers: 2 },
|
|
projects: [{ id: 1, title: 'پروژه نمونه رابط', status: 'in_progress', health: 'at_risk', progress: 62, total_tasks: 14, completed_tasks: 8, overdue_tasks: 2, blocked_tasks: 1 }],
|
|
sprints: [{ id: 1, title: 'Sprint رابط', project: 'پروژه نمونه رابط', progress: 58, expected_progress: 65, remaining_days: 5, health: 'on_track', blocked_tasks: 0 }],
|
|
workload: [{ id: 1, name: 'کاربر نمونه', open_tasks: 7, overdue_tasks: 1, load: 'high' }],
|
|
attention: [],
|
|
upcoming_meetings: [],
|
|
trends: [{ month: '2026-06', created: 12, completed: 9 }, { month: '2026-07', created: 14, completed: 13 }],
|
|
} } });
|
|
if (path === '/api/calendar/events') return route.fulfill({ json: { success: true, data: [] } });
|
|
if (path === '/api/notifications') return route.fulfill({ json: { success: true, data: [], meta: { unread_count: 0, archived_count: 0 } } });
|
|
if (path === '/api/settings') return route.fulfill({ json: { success: true, data: [
|
|
{ id: 1, key: 'working_days', value: ['saturday', 'sunday'], group: 'calendar', type: 'list' },
|
|
{ id: 2, key: 'default_meeting_reminder_minutes', value: 30, group: 'meeting', type: 'number' },
|
|
] } });
|
|
return route.fulfill({ json: { success: true, data: [] } });
|
|
});
|
|
|
|
await page.goto('/');
|
|
await expect(page.getByText('مانیتورینگ عملیاتی')).toBeVisible();
|
|
await expect(page.locator('img.sidebar-brand-mark')).toBeVisible();
|
|
|
|
await page.getByRole('button', { name: 'تقویم رویدادها' }).click();
|
|
await expect(page.getByRole('region', { name: 'تقویم رویدادها' })).toBeVisible();
|
|
await expect(page.getByText('برنامه روز')).toBeVisible();
|
|
await page.mouse.click(900, 760);
|
|
await expect(page.locator('.calendar-popover')).toBeHidden();
|
|
|
|
await page.getByRole('button', { name: 'اعلانها' }).click();
|
|
await expect(page.getByLabel('مرکز اعلانها')).toBeVisible();
|
|
await expect(page.getByText(/برای آرشیو به راست/)).toBeVisible();
|
|
await page.mouse.click(900, 760);
|
|
await expect(page.locator('.notification-center')).toBeHidden();
|
|
|
|
await page.getByRole('button', { name: 'باز کردن پروفایل کاربری' }).click();
|
|
await expect(page.getByRole('dialog', { name: 'پروفایل کاربری' })).toBeVisible();
|
|
await expect(page.getByRole('button', { name: 'ذخیره هویت' })).toBeVisible();
|
|
await page.getByRole('tab', { name: 'اطلاعات کاری' }).click();
|
|
await expect(page.getByRole('button', { name: 'ذخیره اطلاعات کاری' })).toBeVisible();
|
|
const desktopModalMetrics = await page.getByRole('dialog', { name: 'پروفایل کاربری' }).evaluate((element) => {
|
|
const body = element.querySelector('.modal-body');
|
|
const styles = getComputedStyle(element);
|
|
return {
|
|
overflow: styles.overflowY,
|
|
bodyOverflow: getComputedStyle(body).overflowY,
|
|
radius: [styles.borderTopLeftRadius, styles.borderTopRightRadius, styles.borderBottomRightRadius, styles.borderBottomLeftRadius],
|
|
};
|
|
});
|
|
expect(desktopModalMetrics.overflow).toBe('hidden');
|
|
expect(desktopModalMetrics.bodyOverflow).toBe('hidden');
|
|
expect(desktopModalMetrics.radius.every((value) => parseFloat(value) > 0)).toBe(true);
|
|
await page.getByRole('button', { name: 'بستن', exact: true }).click();
|
|
await expect(page.getByRole('dialog', { name: 'پروفایل کاربری' })).toBeHidden();
|
|
|
|
await page.goto('/settings');
|
|
await expect(page.getByRole('heading', { name: 'مرکز تنظیمات' })).toBeVisible();
|
|
await expect(page.getByText('شخصیسازی')).toBeVisible();
|
|
|
|
await page.screenshot({ path: testInfo.outputPath('settings-command-center.png'), fullPage: true });
|
|
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await page.evaluate(() => localStorage.setItem('preferredAppMode', 'desktop'));
|
|
await page.goto('/');
|
|
await expect(page.getByText('مانیتورینگ عملیاتی')).toBeVisible();
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
|
await page.getByRole('button', { name: 'باز کردن منوی اصلی' }).click();
|
|
await expect(page.locator('.app-sidebar.mobile-open')).toBeVisible();
|
|
await expect(page.locator('.app-sidebar.mobile-open').getByText('پروژهها')).toBeVisible();
|
|
await page.locator('.app-sidebar.mobile-open').getByRole('button', { name: 'بستن منوی اصلی' }).click();
|
|
await expect(page.locator('.app-sidebar.mobile-open')).toHaveCount(0);
|
|
await page.getByRole('button', { name: 'باز کردن پروفایل کاربری' }).click();
|
|
await expect(page.getByRole('dialog', { name: 'پروفایل کاربری' })).toBeVisible();
|
|
expect(await page.getByRole('dialog', { name: 'پروفایل کاربری' }).evaluate((element) => element.getBoundingClientRect().height <= window.innerHeight)).toBe(true);
|
|
await page.getByRole('button', { name: 'بستن', exact: true }).click();
|
|
await page.screenshot({ path: testInfo.outputPath('mobile-dashboard.png'), fullPage: true });
|
|
|
|
expect(runtimeErrors).toEqual([]);
|
|
});
|
|
|
|
test('project task can be transferred to an approved project member', async ({ page }) => {
|
|
const assignPermission = { id: 1, name: 'tasks.assign', display_name: 'تخصیص وظایف' };
|
|
const user = {
|
|
id: 1,
|
|
name: 'مدیر پروژه',
|
|
email: 'manager@example.test',
|
|
roles: [{ id: 1, name: 'project_manager', permissions: [assignPermission] }],
|
|
};
|
|
const approvedMember = { id: 2, name: 'عضو تأییدشده', email: 'member@example.test', job_title: 'توسعهدهنده', status: 'active' };
|
|
const project = {
|
|
id: 10,
|
|
title: 'پروژه انتقال تسک',
|
|
description: 'پروژه تست',
|
|
project_manager_id: user.id,
|
|
project_manager: user,
|
|
members: [approvedMember],
|
|
status: 'in_progress',
|
|
priority: 'high',
|
|
progress: 30,
|
|
};
|
|
const task = {
|
|
id: 50,
|
|
title: 'تسک قابل انتقال',
|
|
project_id: project.id,
|
|
assignee_id: user.id,
|
|
assignee: user,
|
|
priority: 'medium',
|
|
status: 'todo',
|
|
due_date: '2026-09-10',
|
|
};
|
|
let assignmentPayload = null;
|
|
|
|
await page.addInitScript(({ testUser }) => {
|
|
localStorage.setItem('token', 'task-assignment-token');
|
|
localStorage.setItem('user', JSON.stringify(testUser));
|
|
}, { testUser: user });
|
|
|
|
await page.route('**/api/**', async (route) => {
|
|
const url = new URL(route.request().url());
|
|
if (url.pathname === '/api/user') return route.fulfill({ json: { success: true, data: user } });
|
|
if (url.pathname === `/api/projects/${project.id}`) return route.fulfill({ json: { success: true, data: project } });
|
|
if (url.pathname === '/api/tasks' && route.request().method() === 'GET') return route.fulfill({ json: { success: true, data: [task] } });
|
|
if (url.pathname === `/api/tasks/${task.id}/assignee` && route.request().method() === 'PUT') {
|
|
assignmentPayload = route.request().postDataJSON();
|
|
return route.fulfill({ json: { success: true, data: { ...task, assignee_id: approvedMember.id, assignee: approvedMember } } });
|
|
}
|
|
return route.fulfill({ json: { success: true, data: [] } });
|
|
});
|
|
|
|
await page.goto(`/projects/${project.id}`);
|
|
await page.getByRole('button', { name: 'تسکها', exact: true }).click();
|
|
const assigneeSelect = page.getByLabel('انتقال مسئول تسک تسک قابل انتقال');
|
|
await expect(assigneeSelect).toBeVisible();
|
|
await assigneeSelect.selectOption(String(approvedMember.id));
|
|
|
|
await expect.poll(() => assignmentPayload?.assignee_id).toBe(approvedMember.id);
|
|
await expect(assigneeSelect).toHaveValue(String(approvedMember.id));
|
|
await expect(page.getByText(/به عضو تأییدشده منتقل شد/)).toBeVisible();
|
|
});
|