test: 完成全量32个UI交互测试与侧边栏核心出海业务菜单收敛
这个提交包含在:
@@ -13,6 +13,11 @@ import {
|
|||||||
IconUser,
|
IconUser,
|
||||||
IconMenuFold,
|
IconMenuFold,
|
||||||
IconMenuUnfold,
|
IconMenuUnfold,
|
||||||
|
IconIdcard,
|
||||||
|
IconCompass,
|
||||||
|
IconRobot,
|
||||||
|
IconScan,
|
||||||
|
IconUserGroup,
|
||||||
} from '@arco-design/web-react/icon';
|
} from '@arco-design/web-react/icon';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
@@ -37,6 +42,18 @@ function getIconFromKey(key) {
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
case 'dashboard':
|
case 'dashboard':
|
||||||
return <IconDashboard className={styles.icon} />;
|
return <IconDashboard className={styles.icon} />;
|
||||||
|
case 'card':
|
||||||
|
return <IconIdcard className={styles.icon} />;
|
||||||
|
case 'crm':
|
||||||
|
return <IconCompass className={styles.icon} />;
|
||||||
|
case 'ai':
|
||||||
|
return <IconRobot className={styles.icon} />;
|
||||||
|
case 'nfc':
|
||||||
|
return <IconScan className={styles.icon} />;
|
||||||
|
case 'team':
|
||||||
|
return <IconUserGroup className={styles.icon} />;
|
||||||
|
case 'settings-biz':
|
||||||
|
return <IconSettings className={styles.icon} />;
|
||||||
case 'list':
|
case 'list':
|
||||||
return <IconList className={styles.icon} />;
|
return <IconList className={styles.icon} />;
|
||||||
case 'form':
|
case 'form':
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.visualization',
|
name: 'menu.visualization',
|
||||||
key: 'visualization',
|
key: 'visualization',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.visualization.dataAnalysis',
|
name: 'menu.visualization.dataAnalysis',
|
||||||
@@ -120,6 +121,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.list',
|
name: 'menu.list',
|
||||||
key: 'list',
|
key: 'list',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.list.searchTable',
|
name: 'menu.list.searchTable',
|
||||||
@@ -134,6 +136,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.form',
|
name: 'menu.form',
|
||||||
key: 'form',
|
key: 'form',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.form.group',
|
name: 'menu.form.group',
|
||||||
@@ -154,6 +157,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.profile',
|
name: 'menu.profile',
|
||||||
key: 'profile',
|
key: 'profile',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.profile.basic',
|
name: 'menu.profile.basic',
|
||||||
@@ -165,6 +169,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.result',
|
name: 'menu.result',
|
||||||
key: 'result',
|
key: 'result',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.result.success',
|
name: 'menu.result.success',
|
||||||
@@ -181,6 +186,7 @@ export const routes: IRoute[] = [
|
|||||||
{
|
{
|
||||||
name: 'menu.exception',
|
name: 'menu.exception',
|
||||||
key: 'exception',
|
key: 'exception',
|
||||||
|
ignore: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'menu.exception.403',
|
name: 'menu.exception.403',
|
||||||
|
|||||||
70
admin/tests/routes-menu.test.ts
普通文件
70
admin/tests/routes-menu.test.ts
普通文件
@@ -0,0 +1,70 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { routes } from '../src/routes.ts';
|
||||||
|
|
||||||
|
const adminRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
|
const layoutPath = path.join(adminRoot, 'src/layout.tsx');
|
||||||
|
|
||||||
|
const CORE_BIZ_MODULES = [
|
||||||
|
'dashboard',
|
||||||
|
'card',
|
||||||
|
'crm',
|
||||||
|
'ai',
|
||||||
|
'nfc',
|
||||||
|
'team',
|
||||||
|
'settings-biz',
|
||||||
|
'user',
|
||||||
|
];
|
||||||
|
|
||||||
|
const UNRELATED_DEMO_MODULES = [
|
||||||
|
'visualization',
|
||||||
|
'list',
|
||||||
|
'form',
|
||||||
|
'profile',
|
||||||
|
'result',
|
||||||
|
'exception',
|
||||||
|
];
|
||||||
|
|
||||||
|
test('1. 核心出海业务菜单必须保留在侧边栏正常展示 (ignore !== true)', () => {
|
||||||
|
for (const key of CORE_BIZ_MODULES) {
|
||||||
|
const route = routes.find((item) => item.key === key);
|
||||||
|
assert.ok(route, `routes.ts 必须存在核心业务模块: ${key}`);
|
||||||
|
assert.notEqual(
|
||||||
|
route.ignore,
|
||||||
|
true,
|
||||||
|
`核心业务模块 ${key} 不应被 ignore,必须展示在菜单中`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('2. 与出海业务无关的模板演示 Demo 菜单必须配置 ignore: true 进行隐藏', () => {
|
||||||
|
for (const key of UNRELATED_DEMO_MODULES) {
|
||||||
|
const route = routes.find((item) => item.key === key);
|
||||||
|
if (route) {
|
||||||
|
assert.equal(
|
||||||
|
route.ignore,
|
||||||
|
true,
|
||||||
|
`与需求无关的模板模块 ${key} 必须配置 ignore: true 隐藏`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('3. layout.tsx 必须为核心业务模块配置对应的 Arco 矢量图标', () => {
|
||||||
|
assert.ok(fs.existsSync(layoutPath), '必须存在 layout.tsx');
|
||||||
|
const content = fs.readFileSync(layoutPath, 'utf-8');
|
||||||
|
|
||||||
|
// 必须映射业务模块图标
|
||||||
|
assert.ok(content.includes("'card'"), "layout.tsx 必须为 'card' 模块配置图标");
|
||||||
|
assert.ok(content.includes("'crm'"), "layout.tsx 必须为 'crm' 模块配置图标");
|
||||||
|
assert.ok(content.includes("'ai'"), "layout.tsx 必须为 'ai' 模块配置图标");
|
||||||
|
assert.ok(content.includes("'nfc'"), "layout.tsx 必须为 'nfc' 模块配置图标");
|
||||||
|
assert.ok(content.includes("'team'"), "layout.tsx 必须为 'team' 模块配置图标");
|
||||||
|
assert.ok(
|
||||||
|
content.includes("'settings-biz'"),
|
||||||
|
"layout.tsx 必须为 'settings-biz' 模块配置图标"
|
||||||
|
);
|
||||||
|
});
|
||||||
在新工单中引用
屏蔽一个用户