150 lines
6.7 KiB
TypeScript
150 lines
6.7 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
|
|
const modules = [
|
|
['/devices', '/goauto/devices/index', 'GoAutoDeviceList', '设备列表', 'monitor'],
|
|
['/pdd-products', '/goauto/pdd-products/index', 'GoAutoPddProducts', 'PDD 商品', 'shopping'],
|
|
['/shopee-products', '/goauto/shopee-products/index', 'GoAutoShopeeProducts', '虾皮商品', 'goods'],
|
|
['/syb-products', '/goauto/syb-products/index', 'GoAutoSybProducts', 'SYB 商品', 'tickets'],
|
|
['/syb-shops', '/goauto/syb-shops/index', 'GoAutoSybShops', 'SYB 店铺', 'shopping'],
|
|
['/syb-sync-runs', '/goauto/syb-sync-runs/index', 'GoAutoSybSyncRuns', 'SYB 同步记录', 'time'],
|
|
['/syb-inner-codes', '/goauto/syb-inner-codes/index', 'GoAutoSybInnerCodes', '档口入库码', 'list'],
|
|
['/collection-rules', '/goauto/collection-rules/index', 'GoAutoCollectionRules', '采集规则', 'code'],
|
|
['/collection-tasks', '/goauto/collection-tasks/index', 'GoAutoCollectionTasks', '采集任务', 'list'],
|
|
['/purchase-tasks', '/goauto/purchase-tasks/index', 'GoAutoPurchaseTasks', '采购管理', 'shopping'],
|
|
['/ai-matching-settings', '/goauto/ai-matching-settings/index', 'GoAutoAiMatchingSettings', 'AI 规格匹配', 'setting']
|
|
] as const
|
|
|
|
const menuGroups = [
|
|
{
|
|
path: '/collection-purchase',
|
|
name: 'GoAutoCollectionPurchase',
|
|
title: '采集采购',
|
|
icon: 'shopping',
|
|
modules: [modules[3], modules[5], modules[6], modules[2], modules[1], modules[8], modules[9]]
|
|
},
|
|
{
|
|
path: '/collection-management',
|
|
name: 'GoAutoCollectionManagement',
|
|
title: '采采管理',
|
|
icon: 'system',
|
|
modules: [modules[4], modules[7], modules[0], modules[10]]
|
|
}
|
|
] as const
|
|
|
|
function childMenu(module: typeof modules[number]) {
|
|
const [path, component, name, title, icon] = module
|
|
return {
|
|
path: `${path}/index`,
|
|
component,
|
|
visible: '0',
|
|
menuName: name,
|
|
title,
|
|
icon
|
|
}
|
|
}
|
|
|
|
function groupedMenus(visibleModules: typeof modules[number][]) {
|
|
const allowed = new Set(visibleModules.map(module => module[2]))
|
|
return menuGroups.flatMap(group => {
|
|
const children = group.modules.filter(module => allowed.has(module[2])).map(childMenu)
|
|
if (children.length === 0) return []
|
|
return [{
|
|
path: group.path,
|
|
component: 'Layout',
|
|
visible: '0',
|
|
menuName: group.name,
|
|
title: group.title,
|
|
icon: group.icon,
|
|
children
|
|
}]
|
|
})
|
|
}
|
|
|
|
async function mockSession(page: any, role: 'admin' | 'purchaser', visibleModules: typeof modules[number][]) {
|
|
await page.context().addCookies([{
|
|
name: 'Admin-Token',
|
|
value: 'menu-permission-test-token',
|
|
domain: 'localhost',
|
|
path: '/'
|
|
}])
|
|
await page.route('**/api/**', async (route: any) => {
|
|
const url = new URL(route.request().url())
|
|
if (url.pathname.startsWith('/src/api/')) return route.continue()
|
|
if (url.pathname.endsWith('/api/v1/getinfo')) {
|
|
return route.fulfill({ json: { code: 200, data: { roles: [role], name: role, avatar: '', introduction: '', permissions: [] } } })
|
|
}
|
|
if (url.pathname.endsWith('/api/v1/menurole')) {
|
|
return route.fulfill({ json: { code: 200, data: groupedMenus(visibleModules) } })
|
|
}
|
|
return route.fulfill({ json: { code: 200, data: [] } })
|
|
})
|
|
}
|
|
|
|
test('管理员深链接展开所属分组并保留全部 GoAuto 页面', async ({ page }) => {
|
|
await mockSession(page, 'admin', [...modules])
|
|
await page.goto('/#/pdd-products/index')
|
|
|
|
await expect(page).toHaveURL(/#\/pdd-products\/index$/)
|
|
await expect(page.locator('.sidebar-container').getByText('采集采购', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('采采管理', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('PDD 商品', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container .is-active').getByText('PDD 商品', { exact: true })).toBeVisible()
|
|
|
|
await page.goto('/#/ai-matching-settings/index')
|
|
await expect(page).toHaveURL(/#\/ai-matching-settings\/index$/)
|
|
await expect(page.locator('.sidebar-container').getByText('AI 规格匹配', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container .is-active').getByText('AI 规格匹配', { exact: true })).toBeVisible()
|
|
})
|
|
|
|
test('采购员只看到授权菜单且不能通过地址访问 AI 配置', async ({ page }) => {
|
|
const purchaserModules = modules.filter(module => module[2] !== 'GoAutoAiMatchingSettings')
|
|
await mockSession(page, 'purchaser', purchaserModules)
|
|
await page.goto('/#/devices/index')
|
|
|
|
await expect(page.locator('.sidebar-container').getByText('采集采购', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('采采管理', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('SYB 店铺', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('设备列表', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('AI 规格匹配', { exact: true })).toHaveCount(0)
|
|
|
|
await page.goto('/#/ai-matching-settings/index')
|
|
await expect(page).toHaveURL(/#\/dashboard$/)
|
|
await expect(page.locator('.sidebar-container').getByText('AI 规格匹配', { exact: true })).toHaveCount(0)
|
|
})
|
|
|
|
test('没有 GoAuto 菜单权限时仍可进入工作台', async ({ page }) => {
|
|
await mockSession(page, 'purchaser', [])
|
|
await page.goto('/#/purchase-tasks/index')
|
|
|
|
await expect(page).toHaveURL(/#\/dashboard$/)
|
|
await expect(page.getByText('工作台', { exact: true }).first()).toBeVisible()
|
|
await expect(page.locator('.sidebar-container').getByText('采购管理', { exact: true })).toHaveCount(0)
|
|
})
|
|
|
|
test('角色菜单加载失败时清除会话并返回登录页', async ({ page }) => {
|
|
await page.context().addCookies([{
|
|
name: 'Admin-Token',
|
|
value: 'menu-permission-test-token',
|
|
domain: 'localhost',
|
|
path: '/'
|
|
}])
|
|
await page.route('**/api/**', async route => {
|
|
const url = new URL(route.request().url())
|
|
if (url.pathname.startsWith('/src/api/')) return route.continue()
|
|
if (url.pathname.endsWith('/api/v1/getinfo')) {
|
|
return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: 'admin', avatar: '', introduction: '', permissions: [] } } })
|
|
}
|
|
if (url.pathname.endsWith('/api/v1/menurole')) {
|
|
return route.fulfill({ json: { code: 500, message: '菜单服务不可用' } })
|
|
}
|
|
return route.fulfill({ json: { code: 200, data: [] } })
|
|
})
|
|
|
|
await page.goto('/#/dashboard')
|
|
await expect(page).toHaveURL(/#\/login\?redirect=\/dashboard$/)
|
|
await expect.poll(async () => {
|
|
const cookies = await page.context().cookies()
|
|
return cookies.some(cookie => cookie.name === 'Admin-Token')
|
|
}).toBe(false)
|
|
})
|