Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
149 lines
5.0 KiB
TypeScript
149 lines
5.0 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 a private consumer route to home with auth modal intent', async ({ page }) => {
|
|
await page.route('**/api/v1/**', (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ success: true, data: { items: [], meta: {} } }),
|
|
})
|
|
)
|
|
await page.goto('/chats')
|
|
|
|
await expect(page).toHaveURL(/\/(\?|$)/)
|
|
await expect(page).not.toHaveURL(/\/auth/)
|
|
await expect(page.getByPlaceholder('مثال ۰۹۱۲۳۴۵۶۷۸۹')).toBeVisible()
|
|
})
|
|
|
|
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('allows public discovery routes without a session', async ({ page }) => {
|
|
await page.route('**/api/v1/**', (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ success: true, data: { items: [], meta: {} } }),
|
|
})
|
|
)
|
|
const response = await page.goto('/')
|
|
|
|
await expect(page).toHaveURL('http://127.0.0.1:3102/')
|
|
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('http://127.0.0.1:3102/')
|
|
})
|
|
|
|
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('http://127.0.0.1:3102/')
|
|
})
|
|
|
|
test('redirects an admin away from the consumer shell', async ({ context, page }) => {
|
|
await authenticate(context, page, 'admin')
|
|
await page.goto('/')
|
|
|
|
await expect(page).toHaveURL(/\/dashboard$/)
|
|
})
|
|
|
|
test('forces pending consumers to complete profile in the auth modal', async ({ context, page }) => {
|
|
const accessToken = createAccessToken('user')
|
|
|
|
await context.addCookies([
|
|
{ name: 'accessToken', value: accessToken, domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userRole', value: 'user', domain: '127.0.0.1', path: '/' },
|
|
{ name: 'userStatus', value: 'pending', 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: 'pending',
|
|
})
|
|
)
|
|
},
|
|
{ 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('/profile')
|
|
|
|
await expect(page).toHaveURL(/\/profile$/)
|
|
await expect(page.getByText('تکمیل اطلاعات پروفایل')).toBeVisible()
|
|
})
|