CRM/frontend/e2e/mobile-shell-calendar.spec.ts

128 خطوط
7.8 KiB
TypeScript
خام پیوند همیشگی سرزنش تاریخچه

مخزن ambiguous runes header

راهنمای مخزن ambiguous runes توضیحات

import { expect, test } from './fixtures'
test.use({ viewport: { width: 390, height: 844 } })
test('mobile shell exposes floating navigation, notification sheet, calendar and date picker', async ({ page }) => {
const now = new Date().toISOString()
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: 11, name: 'کارشناس موبایل', email: 'agent@example.test', phone: null, avatar: null,
roles: ['agent'], permissions: ['view_agent_dashboard', 'view_leads', 'view_own_tasks', 'create_tasks'],
is_active: true, team_id: 2, created_at: '', updated_at: '',
} } })
if (url.pathname === '/api/settings/public') return route.fulfill({ json: { data: {} } })
if (url.pathname === '/api/notifications/unread-count') return route.fulfill({ json: { data: 1 } })
if (url.pathname === '/api/notifications') return route.fulfill({ json: paginated([{
id: 81, type: 'task_assigned', title: 'کار جدید', message: 'پیگیری قرارداد', data: { url: '/tasks' },
is_read: false, read_at: null, created_at: now,
}]) })
if (url.pathname === '/api/calendar/events') return route.fulfill({ json: { events: [{
id: 'task-31', entity_id: 31, type: 'task', title: 'پیگیری قرارداد', starts_at: now,
status: 'open', priority: 'normal', assignee: { id: 11, name: 'کارشناس موبایل' }, related: null, url: '/tasks',
}] } })
if (url.pathname === '/api/tasks') return route.fulfill({ json: paginated([]) })
if (url.pathname === '/api/users/assignable') return route.fulfill({ json: { data: [] } })
return route.fulfill({ json: { data: {} } })
})
await page.goto('/tasks')
await expect(page.getByRole('navigation', { name: 'ناوبری اصلی موبایل' })).toBeVisible()
await expect(page.locator('aside')).toBeHidden()
await expect(page.getByRole('button', { name: 'تقویم کارها و پیگیری‌ها' })).toBeVisible()
await page.getByRole('button', { name: 'تقویم کارها و پیگیری‌ها' }).click()
await expect(page).toHaveURL(/\/calendar$/)
await page.getByRole('tab', { name: 'برنامه روز' }).click()
await expect(page.getByRole('button').filter({ hasText: 'پیگیری قرارداد' }).last()).toBeVisible()
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth === document.documentElement.clientWidth)).toBe(true)
const calendarDialog = page.getByRole('dialog', { name: 'تقویم کارها و پیگیری‌ها' })
await calendarDialog.getByRole('button', { name: 'بستن' }).click()
await expect(calendarDialog).toBeHidden()
await expect(page).toHaveURL(/\/tasks$/)
await page.getByRole('button', { name: /اعلان خوانده‌نشده/ }).click()
const notificationDialog = page.getByRole('dialog', { name: 'اعلان‌ها' })
await expect(notificationDialog).toBeVisible()
await expect(notificationDialog.getByText('کار جدید')).toBeVisible()
const notificationBox = await notificationDialog.boundingBox()
expect(notificationBox?.x).toBeGreaterThanOrEqual(12)
expect(notificationBox ? 390 - notificationBox.x - notificationBox.width : 0).toBeGreaterThanOrEqual(12)
await page.keyboard.press('Escape')
await expect(page.getByRole('dialog', { name: 'اعلان‌ها' })).toBeHidden()
await expect(page.getByRole('heading', { name: 'مرکز کارها' })).toBeVisible()
await page.getByRole('button', { name: 'کار جدید' }).click()
await page.getByLabel('موضوع کار').fill('کار آزمایشی')
await page.getByRole('button', { name: 'ادامه' }).click()
await page.getByRole('button', { name: /^موعد:/ }).click()
await expect(page.getByRole('dialog', { name: 'موعد' })).toBeVisible()
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth === document.documentElement.clientWidth)).toBe(true)
await page.getByRole('button', { name: 'امروز' }).click()
await expect(page.getByRole('button', { name: /^موعد:/ })).not.toContainText('انتخاب تاریخ و ساعت')
})
test('selected calendar day number stays visible in dark mode', async ({ page }) => {
await page.addInitScript(() => localStorage.setItem('theme', 'dark'))
await page.route('**/api/**', async (route) => {
const url = new URL(route.request().url())
if (!url.pathname.startsWith('/api/')) return route.continue()
if (url.pathname === '/api/auth/me') return route.fulfill({ json: { data: {
id: 11, name: 'کارشناس موبایل', email: 'agent@example.test', roles: ['agent'],
permissions: ['view_agent_dashboard', 'view_leads', 'view_own_tasks'], is_active: true,
} } })
if (url.pathname === '/api/settings/public') return route.fulfill({ json: { data: {} } })
if (url.pathname === '/api/notifications/unread-count') return route.fulfill({ json: { data: 0 } })
if (url.pathname === '/api/calendar/events') return route.fulfill({ json: { events: [] } })
return route.fulfill({ json: { data: [] } })
})
await page.goto('/calendar')
const selectedNumber = page.locator('button[aria-pressed="true"] > span').first()
await expect(selectedNumber).toBeVisible()
const colors = await selectedNumber.evaluate((element) => {
const style = getComputedStyle(element)
return { foreground: style.color, background: style.backgroundColor, text: element.textContent?.trim() }
})
expect(colors.text).toBeTruthy()
expect(colors.background).not.toBe('rgba(0, 0, 0, 0)')
expect(colors.foreground).not.toBe(colors.background)
})
test('desktop calendar keeps the first event readable inside its day cell', async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 820 })
const now = new Date().toISOString()
await page.route('**/api/**', async (route) => {
const url = new URL(route.request().url())
if (!url.pathname.startsWith('/api/')) return route.continue()
if (url.pathname === '/api/auth/me') return route.fulfill({ json: { data: {
id: 11, name: 'کارشناس تقویم', email: 'agent@example.test', roles: ['agent'],
permissions: ['view_agent_dashboard', 'view_leads', 'view_own_tasks'], is_active: true,
} } })
if (url.pathname === '/api/settings/public') return route.fulfill({ json: { data: {} } })
if (url.pathname === '/api/notifications/unread-count') return route.fulfill({ json: { data: 0 } })
if (url.pathname === '/api/calendar/events') return route.fulfill({ json: { events: [
{ id: 'task-1', entity_id: 1, type: 'task', title: 'رویداد قابل خواندن', starts_at: now, status: 'open', priority: 'normal', assignee: null, related: null, url: '/tasks' },
{ id: 'follow-2', entity_id: 2, type: 'follow_up', title: 'پیگیری دوم', starts_at: now, status: 'pending', assignee: null, related: null, url: '/follow-ups' },
] } })
return route.fulfill({ json: { data: [] } })
})
await page.goto('/calendar')
const event = page.locator('span[title="رویداد قابل خواندن"]')
await expect(event).toBeVisible()
await expect(page.getByText('+۱ مورد دیگر')).toBeVisible()
const cell = event.locator('xpath=ancestor::button[1]')
const eventBox = await event.boundingBox()
const cellBox = await cell.boundingBox()
expect(eventBox?.height).toBeGreaterThanOrEqual(12)
expect(eventBox?.y).toBeGreaterThanOrEqual(cellBox?.y ?? 0)
expect((eventBox?.y ?? 0) + (eventBox?.height ?? 0)).toBeLessThanOrEqual((cellBox?.y ?? 0) + (cellBox?.height ?? 0))
})
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 } }
}