205 خطوط
10 KiB
TypeScript
205 خطوط
10 KiB
TypeScript
import { expect, test } from './fixtures'
|
|
|
|
test('supervisor creates an assigned task from Task Center', async ({ page }) => {
|
|
let createdTask: Record<string, unknown> | null = null
|
|
const pageErrors: string[] = []
|
|
page.on('pageerror', (error) => pageErrors.push(error.message))
|
|
page.on('console', (message) => { if (message.type() === 'error') pageErrors.push(message.text()) })
|
|
|
|
await page.route('**/api/**', async (route) => {
|
|
const request = route.request()
|
|
const url = new URL(request.url())
|
|
if (!url.pathname.startsWith('/api/')) return route.continue()
|
|
|
|
if (url.pathname === '/api/auth/me') {
|
|
return route.fulfill({ json: { data: {
|
|
id: 7, name: 'سرپرست تست', email: 'supervisor@example.test', phone: null,
|
|
voip_extension: null, avatar: null, is_active: true, last_login_at: null,
|
|
roles: ['supervisor'], team_id: 2, created_at: '', updated_at: '',
|
|
permissions: ['view_team_tasks', 'create_tasks', 'assign_tasks', 'bulk_manage_tasks'],
|
|
} } })
|
|
}
|
|
|
|
if (url.pathname === '/api/users/assignable') {
|
|
return route.fulfill({ json: { data: [{
|
|
id: 11, name: 'کارشناس تیم', avatar: null, role_label: 'کارشناس',
|
|
team_label: 'فروش', is_active: true, open_tasks_count: 2,
|
|
}] } })
|
|
}
|
|
|
|
if (url.pathname === '/api/tasks' && request.method() === 'POST') {
|
|
const body = request.postDataJSON()
|
|
createdTask = task({ id: 31, subject: body.subject, assigned_to: body.assigned_to })
|
|
return route.fulfill({ status: 201, json: { data: createdTask } })
|
|
}
|
|
|
|
if (url.pathname === '/api/tasks') {
|
|
const tasks = createdTask ? [createdTask] : []
|
|
return route.fulfill({ json: { data: tasks, meta: {
|
|
current_page: 1, last_page: 1, per_page: 20, total: tasks.length,
|
|
from: tasks.length ? 1 : 0, to: tasks.length,
|
|
} } })
|
|
}
|
|
|
|
if (url.pathname === '/api/notifications/unread-count') return route.fulfill({ json: { data: { count: 0 } } })
|
|
if (url.pathname === '/api/settings/public') return route.fulfill({ json: { data: {} } })
|
|
return route.fulfill({ json: { data: [] } })
|
|
})
|
|
|
|
await page.goto('/tasks')
|
|
await page.waitForTimeout(500)
|
|
expect(pageErrors, `Browser errors: ${pageErrors.join(' | ')}`).toEqual([])
|
|
await expect(page).toHaveURL(/\/tasks$/)
|
|
expect(await page.locator('body').innerText()).toContain('مرکز کارها')
|
|
await page.getByRole('button', { name: 'کار جدید' }).click()
|
|
await page.getByLabel('موضوع کار').fill('پیگیری قرارداد آزمایشی')
|
|
await page.getByText('کارشناس تیم').click()
|
|
await page.getByRole('button', { name: 'ادامه' }).click()
|
|
await page.getByRole('button', { name: 'ایجاد کار' }).click()
|
|
|
|
await expect(page.getByText('پیگیری قرارداد آزمایشی')).toBeVisible()
|
|
})
|
|
|
|
test('agent opens an assignment notification, starts and completes the task, then supervisor sees it', async ({ page }) => {
|
|
let role: 'agent' | 'supervisor' = 'agent'
|
|
let status: 'open' | 'in_progress' | 'done' = 'open'
|
|
let version = 1
|
|
let notificationRead = false
|
|
|
|
await page.route('**/api/**', async (route) => {
|
|
const request = route.request()
|
|
const url = new URL(request.url())
|
|
if (!url.pathname.startsWith('/api/')) return route.continue()
|
|
|
|
if (url.pathname === '/api/auth/me') {
|
|
return route.fulfill({ json: { data: user(role, role === 'agent'
|
|
? ['view_own_tasks', 'edit_own_tasks', 'complete_tasks']
|
|
: ['view_team_tasks', 'edit_team_tasks', 'complete_tasks']) } })
|
|
}
|
|
if (url.pathname === '/api/notifications') {
|
|
return route.fulfill({ json: paginated([{
|
|
id: 81, title: 'کار جدید به شما تخصیص یافت', message: 'پیگیری مشتری',
|
|
type: 'task_assigned', data: { url: '/tasks?task=31', task_id: 31 },
|
|
is_read: notificationRead, read_at: notificationRead ? new Date().toISOString() : null,
|
|
created_at: new Date().toISOString(),
|
|
}]) })
|
|
}
|
|
if (url.pathname === '/api/notifications/81/read') {
|
|
notificationRead = true
|
|
return route.fulfill({ json: { data: { read_at: new Date().toISOString() } } })
|
|
}
|
|
if (url.pathname === '/api/notifications/unread-count') {
|
|
return route.fulfill({ json: { data: notificationRead ? 0 : 1 } })
|
|
}
|
|
if (url.pathname === '/api/tasks/31/start') {
|
|
status = 'in_progress'; version += 1
|
|
return route.fulfill({ json: { data: task({ id: 31, subject: 'پیگیری مشتری', status, version }) } })
|
|
}
|
|
if (url.pathname === '/api/tasks/31/complete') {
|
|
status = 'done'; version += 1
|
|
return route.fulfill({ json: { data: task({ id: 31, subject: 'پیگیری مشتری', status, version }) } })
|
|
}
|
|
if (url.pathname === '/api/tasks/31') {
|
|
return route.fulfill({ json: { data: task({ id: 31, subject: 'پیگیری مشتری', status, version }) } })
|
|
}
|
|
if (url.pathname === '/api/tasks') {
|
|
return route.fulfill({ json: paginated([task({ id: 31, subject: 'پیگیری مشتری', status, version })]) })
|
|
}
|
|
if (url.pathname === '/api/users/assignable') return route.fulfill({ json: { data: [] } })
|
|
return route.fulfill({ json: { data: {} } })
|
|
})
|
|
|
|
await page.goto('/notifications')
|
|
await expect(page.getByText('کار جدید به شما تخصیص یافت')).toBeVisible()
|
|
await page.getByRole('link', { name: 'باز کردن' }).click()
|
|
await expect(page.getByRole('dialog', { name: 'کار: پیگیری مشتری' })).toBeVisible()
|
|
await page.getByRole('button', { name: 'شروع کار' }).click()
|
|
await expect(page.getByRole('cell', { name: 'در حال انجام' })).toBeVisible()
|
|
await page.getByRole('button', { name: 'مشاهده' }).click()
|
|
await page.getByRole('button', { name: 'تکمیل کار' }).click()
|
|
await page.getByRole('button', { name: 'ادامه و بررسی نهایی' }).click()
|
|
await page.getByRole('button', { name: 'اجرای تغییر وضعیت' }).click()
|
|
await expect(page.getByRole('cell', { name: 'انجامشده' })).toBeVisible()
|
|
|
|
role = 'supervisor'
|
|
await page.reload()
|
|
await expect(page.getByRole('cell', { name: 'انجامشده' })).toBeVisible()
|
|
})
|
|
|
|
test('agent adds a call note while out-of-scope task and call details stay closed', async ({ page }) => {
|
|
let notes: Record<string, unknown>[] = []
|
|
let denyDirectAccess = false
|
|
const call = {
|
|
id: 51, user_id: 11, lead_id: 21, direction: 'outbound', status: 'completed',
|
|
duration_seconds: 45, result: 'answered', notes: null, started_at: null,
|
|
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
|
|
agent: { id: 11, name: 'کارشناس تیم' }, lead: { id: 21, first_name: 'رضا', last_name: 'محمدی' },
|
|
}
|
|
|
|
await page.route('**/api/**', async (route) => {
|
|
const request = route.request()
|
|
const url = new URL(request.url())
|
|
if (!url.pathname.startsWith('/api/')) return route.continue()
|
|
if (url.pathname === '/api/auth/me') return route.fulfill({ json: { data: user('agent', ['view_own_calls', 'view_own_tasks', 'manage_call_notes']) } })
|
|
if (url.pathname === '/api/calls' && !denyDirectAccess) return route.fulfill({ json: paginated([call]) })
|
|
if (url.pathname === '/api/calls/51' && !denyDirectAccess) return route.fulfill({ json: { data: call } })
|
|
if (url.pathname === '/api/calls/51/notes' && request.method() === 'POST') {
|
|
const body = request.postDataJSON()
|
|
notes = [{ id: 91, content: body.content, type: body.type, visibility: body.visibility,
|
|
is_pinned: false, author: { id: 11, name: 'کارشناس تیم' }, edited_at: null,
|
|
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
|
|
capabilities: { edit: true, delete: true, pin: false } }]
|
|
return route.fulfill({ status: 201, json: { data: notes[0] } })
|
|
}
|
|
if (url.pathname === '/api/calls/51/notes') return route.fulfill({ json: { data: notes } })
|
|
if (url.pathname === '/api/tasks/999' || url.pathname === '/api/calls/999') {
|
|
return route.fulfill({ status: 403, json: { message: 'Forbidden' } })
|
|
}
|
|
if (url.pathname === '/api/tasks') return route.fulfill({ json: paginated([]) })
|
|
if (url.pathname === '/api/calls' && denyDirectAccess) return route.fulfill({ json: paginated([{ ...call, id: 999 }]) })
|
|
if (url.pathname === '/api/notifications/unread-count') return route.fulfill({ json: { data: 0 } })
|
|
return route.fulfill({ json: { data: {} } })
|
|
})
|
|
|
|
await page.goto('/calls')
|
|
await page.getByText('رضا محمدی').click()
|
|
await page.getByLabel('یادداشت جدید تماس').fill('تعهد به ارسال قرارداد')
|
|
await page.getByRole('button', { name: 'ثبت یادداشت' }).click()
|
|
await expect(page.getByText('تعهد به ارسال قرارداد')).toBeVisible()
|
|
|
|
denyDirectAccess = true
|
|
await page.goto('/tasks?task=999')
|
|
await expect(page.getByRole('dialog')).toHaveCount(0)
|
|
await page.goto('/calls')
|
|
await page.getByText('رضا محمدی').click()
|
|
await expect(page.getByRole('dialog')).toHaveCount(0)
|
|
})
|
|
|
|
function task(overrides: Record<string, unknown>) {
|
|
return {
|
|
id: 1, subject: 'کار', description: null, taskable_type: null, taskable_id: null,
|
|
taskable: null, assigned_to: null, assignee: { id: 11, name: 'کارشناس تیم' },
|
|
assigned_by: 7, assigner: { id: 7, name: 'سرپرست تست' }, created_by: 7,
|
|
creator: { id: 7, name: 'سرپرست تست' }, priority: 'normal', status: 'open',
|
|
due_at: null, started_at: null, completed_at: null, reminder_at: null,
|
|
parent_task_id: null, parent: null, estimated_minutes: null, visibility: 'team',
|
|
version: 1, is_overdue: false,
|
|
capabilities: { update: true, assign: true, transition: true, delete: true },
|
|
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
function paginated(items: Record<string, unknown>[]) {
|
|
return { data: items, meta: { current_page: 1, last_page: 1, per_page: 20, total: items.length, from: items.length ? 1 : 0, to: items.length } }
|
|
}
|
|
|
|
function user(role: 'agent' | 'supervisor', permissions: string[]) {
|
|
return {
|
|
id: role === 'agent' ? 11 : 7, name: role === 'agent' ? 'کارشناس تیم' : 'سرپرست تست',
|
|
email: `${role}@example.test`, phone: null, voip_extension: null, avatar: null,
|
|
is_active: true, last_login_at: null, roles: [role], permissions, team_id: 2,
|
|
created_at: '', updated_at: '',
|
|
}
|
|
}
|