- Introduced layout components for multiple admin dashboard sections including events, audit logs, bank accounts, blog articles, bookings, chat oversight, cities, contact messages, dashboard, discount codes, event categories, guest lists, identity verifications, manage events, manual notifications, notification rules, payments, provinces, push deliveries, reviews, settlements, sms messages, support tickets, user reports, and users. - Updated metadata for the auth layout to include the admin page title. - Modified branch protection documentation to clarify deployment notifications.
88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
import { expect, test, type BrowserContext, type Page } from '@playwright/test'
|
|
|
|
import { authenticateAs, createAccessToken } from '@/e2e/fixtures/session'
|
|
|
|
const authenticate = async (context: BrowserContext, page: Page, role: 'admin' | 'user', status: 'active' | 'pending' = 'active') => {
|
|
if (status === 'active') {
|
|
await authenticateAs(context, page, role)
|
|
|
|
return
|
|
}
|
|
|
|
await context.addCookies([
|
|
{ name: 'accessToken', value: createAccessToken(role), domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userRole', value: role, domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userStatus', value: status, domain: '127.0.0.1', path: '/' },
|
|
])
|
|
}
|
|
|
|
test('redirects a guest from an admin route to the admin auth page', async ({ page }) => {
|
|
await page.goto('/dashboard')
|
|
|
|
await expect(page).toHaveURL(/\/auth\?redirect=%2Fdashboard$/)
|
|
// Auth mobile step has no page title — assert the OTP entry form instead.
|
|
await expect(page.getByLabel('شماره موبایل')).toBeVisible()
|
|
await expect(page.getByRole('button', { name: 'ادامه' })).toBeVisible()
|
|
})
|
|
|
|
test('root redirects guests toward auth via the dashboard gate', async ({ page }) => {
|
|
const response = await page.goto('/')
|
|
|
|
await expect(page).toHaveURL(/\/auth/)
|
|
await expect(page.locator('body')).toBeVisible()
|
|
expect(response?.headers()['content-security-policy']).toContain("frame-ancestors 'none'")
|
|
expect(response?.headers()['x-content-type-options']).toBe('nosniff')
|
|
expect(response?.headers()['referrer-policy']).toBe('strict-origin-when-cross-origin')
|
|
})
|
|
|
|
test('prevents a consumer from opening admin routes', async ({ context, page }) => {
|
|
await authenticate(context, page, 'user')
|
|
await page.goto('/dashboard')
|
|
|
|
await expect(page).toHaveURL(/\/auth/)
|
|
})
|
|
|
|
test('ignores a forged userRole=admin cookie when the access JWT is a consumer', async ({ context, page }) => {
|
|
const accessToken = createAccessToken('user')
|
|
|
|
await context.addCookies([
|
|
{ name: 'accessToken', value: accessToken, domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userRole', value: 'admin', domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userStatus', value: 'active', domain: '127.0.0.1', path: '/' },
|
|
])
|
|
await page.addInitScript(
|
|
({ token }) => {
|
|
localStorage.setItem(
|
|
'user',
|
|
JSON.stringify({
|
|
accessToken: token,
|
|
userId: 'user-id',
|
|
role: 'user',
|
|
sessionId: 'user-session',
|
|
AccessTokenExpireTime: Date.now() + 3_600_000,
|
|
refreshTokenExpireTime: Date.now() + 86_400_000,
|
|
status: 'active',
|
|
})
|
|
)
|
|
},
|
|
{ token: accessToken }
|
|
)
|
|
await page.route('**/api/v1/**', (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ success: true, data: { items: [], meta: {} } }),
|
|
})
|
|
)
|
|
await page.goto('/dashboard')
|
|
|
|
await expect(page).toHaveURL(/\/auth/)
|
|
})
|
|
|
|
test('redirects an authenticated admin from root to the dashboard', async ({ context, page }) => {
|
|
await authenticate(context, page, 'admin')
|
|
await page.goto('/')
|
|
|
|
await expect(page).toHaveURL(/\/dashboard$/)
|
|
})
|