import { expect, test } from '@playwright/test' async function login(page: import('@playwright/test').Page, email = 'designer@microlearn.test') { await page.goto('http://127.0.0.1:5173/login') await page.getByLabel(/ایمیل|Email/).fill(email) await page.getByLabel(/رمز عبور|Password/).fill('password') await page.getByRole('button', { name: /ورود|Sign in/ }).click() await expect(page).toHaveURL(/\/(app\/dashboard|admin\/dashboard|manager\/overview)$/) } async function expectWorkspaceWithinViewport(page: import('@playwright/test').Page) { const bounds = await page.locator('.workspace').evaluate(element => { const workspace = element.getBoundingClientRect() const body = element.querySelector('.workspace__body')?.getBoundingClientRect() return { workspaceLeft: workspace.left, workspaceRight: workspace.right, bodyLeft: body?.left ?? 0, bodyRight: body?.right ?? 0, viewportWidth: window.innerWidth, scrollWidth: document.documentElement.scrollWidth, } }) expect(bounds.workspaceLeft).toBeGreaterThanOrEqual(-1) expect(bounds.bodyLeft).toBeGreaterThanOrEqual(-1) expect(bounds.workspaceRight).toBeLessThanOrEqual(bounds.viewportWidth + 1) expect(bounds.bodyRight).toBeLessThanOrEqual(bounds.viewportWidth + 1) expect(bounds.scrollWidth).toBeLessThanOrEqual(bounds.viewportWidth) } test('desktop shell groups navigation, exposes context and preserves RTL/dark mode', async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }) await login(page) await expectWorkspaceWithinViewport(page) const primary = page.getByRole('navigation', { name: 'ناوبری اصلی' }) const create = primary.getByRole('button', { name: 'ساخت' }) await expect(create).toHaveAttribute('aria-expanded', 'true') await create.click() await expect(primary.getByRole('link', { name: 'دوره‌ها' })).toBeHidden() await create.click() const collapse = page.getByRole('button', { name: 'جمع‌کردن نوار کناری' }) await collapse.click() await expect(page.locator('.workspace')).toHaveClass(/workspace--collapsed/) await expectWorkspaceWithinViewport(page) const courseLink = primary.getByRole('link', { name: 'دوره‌ها' }) await expect(courseLink).toHaveAttribute('data-tooltip', 'دوره‌ها') await page.goto('http://127.0.0.1:5173/app/courses/course-1') const breadcrumb = page.getByRole('navigation', { name: 'مسیر صفحه' }) await expect(breadcrumb).toContainText('دوره‌ها') await expect(breadcrumb).toContainText('فضای دوره') await page.getByRole('button', { name: 'انتخاب زبان و تقویم' }).click() await page.getByRole('menuitemradio', { name: 'English' }).click() await page.getByRole('button', { name: 'Choose appearance' }).click() await page.getByRole('menuitemradio', { name: 'Dark' }).click() await expect(page.locator('html')).toHaveAttribute('dir', 'ltr') await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark') expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth)).toBe(true) }) test('mobile drawer announces state, traps focus and restores its trigger', async ({ page }) => { await page.setViewportSize({ width: 375, height: 812 }) await login(page) for (const width of [375, 430, 768, 1024]) { await page.setViewportSize({ width, height: width < 768 ? 812 : 900 }) const trigger = page.getByRole('button', { name: 'باز کردن منو' }) await expect(trigger).toBeVisible() await expect(trigger).toHaveAttribute('aria-expanded', 'false') await trigger.click() await expect(trigger).toHaveAttribute('aria-expanded', 'true') const sidebar = page.locator('.sidebar') await expect(sidebar).toBeVisible() await expect(sidebar.getByRole('button', { name: 'بستن منو' })).toBeFocused() await page.keyboard.press('Escape') await expect(sidebar).toBeHidden() await expect(trigger).toBeFocused() await expect(trigger).toHaveAttribute('aria-expanded', 'false') expect(await page.evaluate(() => document.body.style.overflow), `${width}px body lock`).toBe('') expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth), `${width}px overflow`).toBe(true) } }) test('admin and manager receive distinct role-aware navigation', async ({ page }) => { await login(page, 'admin@microlearn.test') await expect(page.getByRole('navigation', { name: 'ناوبری اصلی' }).getByRole('link', { name: 'سازمان‌ها' })).toBeVisible() await expect(page.getByRole('link', { name: 'دوره‌ها' })).toHaveCount(0) await page.getByRole('button', { name: 'بازکردن حساب کاربری' }).click() await page.getByRole('menuitem', { name: 'خروج از حساب' }).click() await expect(page).toHaveURL(/\/login$/) await login(page, 'manager@microlearn.test') await expect(page.getByRole('navigation', { name: 'ناوبری اصلی' }).getByRole('link', { name: 'تیم من' })).toBeVisible() await expect(page.getByRole('link', { name: 'استودیوی هوش مصنوعی' })).toHaveCount(0) })