gongxiangp2/components/department-dashboard/CoreMetricDetail.test.tsx
2026-08-31 13:17:20 +08:00

376 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { fireEvent, render, screen, within } from '@testing-library/react'
import CoreMetricDetail from './CoreMetricDetail'
import { getCoreMetric } from './core-metrics'
jest.mock('next-auth/react', () => ({
useSession: () => ({ data: { user: { name: '本地超级管理员' } } }),
signOut: jest.fn(),
}))
describe('CoreMetricDetail', () => {
it('按品牌与当前节点处理人展示真实进行中项目', () => {
const metric = getCoreMetric('ongoing-projects')!
render(
<CoreMetricDetail
metric={metric}
projectInsights={{
items: [{
id: 'project-1',
businessId: 'BUSINESS-1',
title: '夏季主视觉过稿',
status: 'RUNNING',
processCode: 'PROC-3571C915-0506-4490-A91A-8AA7EA33F838',
projectType: '美术设计流程',
brand: '亿家达',
requesterName: '林需求',
requesterDepartment: '品牌中心',
initiatorName: '荀瑶',
initiatorDepartment: '运营中心A-事业四部-品类九部-淘系四组',
formFields: {
platform: '天猫',
brand: '自有品牌-亿家达',
category: '书桌',
spu: 'YJD-001',
demandType: '新品',
standardOutputDeadline: '5个工作日',
sourceType: null,
taskType: null,
installVideo: null,
quantity: null,
cameraQuantity: null,
planningTaskStats: null,
graphicTaskStats: null,
imageTaskStats: null,
},
assignmentNodeLabel: '品牌策划主管分配任务',
assignmentStartedAt: '2026-08-11T02:00:00.000Z',
reviewNodeLabel: '品牌策划主管审核',
reviewFinishedAt: null,
originatorUserId: 'ding-1',
originatorDeptName: '品牌中心',
sourceCreatedAt: '2026-08-10T00:00:00.000Z',
sourceUpdatedAt: '2026-08-14T02:30:00.000Z',
activeTaskCount: 1,
taskCount: 3,
schemeFieldCount: 12,
latestTaskStatus: 'RUNNING',
activeTasks: [{
taskId: 'task-1',
activityId: 'activity-1',
nodeName: '部门负责人审批',
assigneeUserId: 'ding-owner-1',
assigneeName: '陈负责人',
assigneeDepartment: '品牌中心/创意设计部',
isBrandCenter: true,
isLeadership: false,
isActive: true,
reviewPassed: false,
result: null,
createdAt: '2026-08-14T02:00:00.000Z',
finishedAt: null,
}],
}],
total: 1,
sync: { total: 1, lastSyncedAt: '2026-08-14T02:30:00.000Z', syncStatus: 'ready' },
}}
/>,
)
expect(screen.getByRole('heading', { level: 1, name: '进行中项目' })).toBeInTheDocument()
expect(screen.getAllByText('夏季主视觉过稿').length).toBeGreaterThan(0)
expect(screen.getAllByText('部门负责人审批').length).toBeGreaterThan(0)
expect(screen.getByRole('columnheader', { name: '审批单标题' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '审批编号' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '需求人' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '需求部门' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '平台' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '品牌' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '类目' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: 'SPU' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '需求类型' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '标准出图最长时效限制' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '分配任务开始时间' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '当前节点名称' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '当前节点负责人' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '审核结束时间' })).toBeInTheDocument()
expect(screen.getAllByText('品牌策划主管分配任务').length).toBeGreaterThan(0)
expect(screen.getAllByText('品牌策划主管审核').length).toBeGreaterThan(0)
expect(screen.getAllByText('自有品牌-亿家达').length).toBeGreaterThan(0)
expect(screen.getAllByText('YJD-001').length).toBeGreaterThan(0)
expect(screen.getByText(/发起时间不早于 2026 年 4 月 1 日的未完结流程快照/)).toBeInTheDocument()
expect(screen.queryByRole('link', { name: /返回核心指标/ })).not.toBeInTheDocument()
fireEvent.click(screen.getByRole('tab', { name: /项目负责人/ }))
expect(screen.getByText('负责人按当前未完结节点的处理人统计;并行处理会分别计入对应人员。')).toBeInTheDocument()
expect(screen.getAllByText('陈负责人').length).toBeGreaterThan(0)
fireEvent.click(screen.getByRole('tab', { name: /发起人维度/ }))
expect(screen.getByText('发起人进行中数量')).toBeInTheDocument()
expect(screen.getByText('发起人按钉钉唯一标识匹配人员架构;所在部门以 HR 花名册为准。')).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '排名' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '发起人' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '所在部门' })).toBeInTheDocument()
expect(screen.getByRole('columnheader', { name: '进行中数量' })).toBeInTheDocument()
expect(screen.getAllByText('荀瑶').length).toBeGreaterThan(0)
expect(screen.getAllByText('运营中心A-事业四部-品类九部-淘系四组').length).toBeGreaterThan(0)
})
it('未接入的指标只展示诚实的明细框架', () => {
render(<CoreMetricDetail metric={getCoreMetric('risks')!} />)
expect(screen.getByRole('heading', { level: 1, name: '风险' })).toBeInTheDocument()
expect(screen.getByText(/当前不展示虚构记录/)).toBeInTheDocument()
expect(screen.getByText('数据源待接入')).toBeInTheDocument()
})
it('按六品牌切换查看本月完成与当前进行中的美术设计流程', () => {
const baseProject = {
businessId: 'BUSINESS-1',
title: '新品主视觉申请',
status: 'COMPLETED',
processCode: 'PROC-3571C915-0506-4490-A91A-8AA7EA33F838',
projectType: '美术设计流程',
brand: '亿家达',
requesterName: '林需求',
requesterDepartment: '品牌中心',
initiatorName: '荀瑶',
initiatorDepartment: '运营中心A-事业四部-品类九部',
formFields: {
platform: '天猫',
brand: '自有品牌-亿家达',
category: '书桌',
spu: 'YJD-001',
demandType: '新品',
standardOutputDeadline: '5个工作日',
sourceType: null,
taskType: null,
installVideo: null,
quantity: null,
cameraQuantity: null,
planningTaskStats: null,
graphicTaskStats: null,
imageTaskStats: null,
},
assignmentNodeLabel: '品牌策划主管分配任务',
assignmentStartedAt: '2026-08-11T02:00:00.000Z',
reviewNodeLabel: '品牌策划主管审核',
reviewFinishedAt: '2026-08-12T03:00:00.000Z',
originatorUserId: 'ding-1',
originatorDeptName: '运营中心A',
sourceCreatedAt: '2026-04-20T00:00:00.000Z',
sourceUpdatedAt: '2026-08-14T02:30:00.000Z',
activeTaskCount: 0,
taskCount: 0,
schemeFieldCount: 0,
latestTaskStatus: null,
activeTasks: [],
result: 'AGREE',
}
render(
<CoreMetricDetail
metric={getCoreMetric('monthly-launches')!}
monthlyLaunches={{
summary: {
completed: 1,
ongoing: 1,
total: 2,
monthStart: '2026-07-31T16:00:00.000Z',
monthEnd: '2026-08-31T16:00:00.000Z',
lastSyncedAt: '2026-08-14T02:30:00.000Z',
syncStatus: 'ready',
},
brands: [
{ brand: '亿家达', completed: 1, ongoing: 1, total: 2 },
{ brand: '卓禾', completed: 0, ongoing: 0, total: 0 },
{ brand: '欧意朗', completed: 0, ongoing: 0, total: 0 },
{ brand: '顾家', completed: 0, ongoing: 0, total: 0 },
{ brand: '索菲亚', completed: 0, ongoing: 0, total: 0 },
{ brand: '朴美', completed: 0, ongoing: 0, total: 0 },
],
items: [
{
...baseProject,
id: 'completed-1',
launchStatus: 'completed',
sourceFinishedAt: '2026-08-12T03:00:00.000Z',
},
{
...baseProject,
id: 'ongoing-1',
businessId: 'BUSINESS-2',
title: '新品场景设计申请',
status: 'RUNNING',
launchStatus: 'ongoing',
sourceFinishedAt: null,
activeTaskCount: 1,
activeTasks: [{
taskId: 'task-1',
activityId: 'activity-1',
nodeName: '品牌负责人审批',
assigneeUserId: 'ding-owner',
assigneeName: '陈负责人',
assigneeDepartment: '品牌中心',
isBrandCenter: true,
isLeadership: false,
isActive: true,
reviewPassed: false,
result: null,
createdAt: '2026-08-14T02:00:00.000Z',
finishedAt: null,
}],
},
],
}}
/>,
)
expect(screen.getByRole('heading', { level: 1, name: '本月上新' })).toBeInTheDocument()
expect(screen.getByText('1/2')).toBeInTheDocument()
expect(screen.getByRole('heading', { name: '亿家达 · 本月已完结新品' })).toBeInTheDocument()
expect(screen.getAllByText('流程已完结').length).toBeGreaterThan(0)
expect(screen.getAllByText('新品主视觉申请').length).toBeGreaterThan(0)
const completedTable = screen.getByRole('table', { name: /亿家达本月已完结新品流程明细横向滚动表格/ })
;[
'审批单标题',
'审批编号',
'需求人',
'需求部门',
'平台',
'品牌',
'类目',
'SPU',
'需求类型',
'标准出图最长时效限制',
'分配任务开始时间',
'当前节点名称',
'当前节点负责人',
'审核结束时间',
].forEach((name) => {
expect(within(completedTable).getByRole('columnheader', { name })).toBeInTheDocument()
})
expect(within(completedTable).getByText('YJD-001')).toBeInTheDocument()
expect(within(completedTable).getByText('5个工作日')).toBeInTheDocument()
expect(within(completedTable).getByText('品牌策划主管审核')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: '查看亿家达当前进行中明细,共1条' }))
expect(screen.getByRole('heading', { name: '亿家达 · 当前进行中新品' })).toBeInTheDocument()
expect(screen.getAllByText('新品场景设计申请').length).toBeGreaterThan(0)
expect(screen.getAllByText(/品牌负责人审批/).length).toBeGreaterThan(0)
const ongoingTable = screen.getByRole('table', { name: /亿家达当前进行中新品流程明细横向滚动表格/ })
expect(within(ongoingTable).getByText('品牌负责人审批')).toBeInTheDocument()
expect(within(ongoingTable).getByText('陈负责人')).toBeInTheDocument()
})
it('在按时交付明细中展示真实公式并只用黄色数值呈现阈值状态', () => {
render(
<CoreMetricDetail
metric={getCoreMetric('on-time-delivery')!}
onTimeDelivery={{
items: [],
summary: {
onTime: 946,
overtime: 54,
pending: 0,
total: 1000,
rate: 94.6,
monthStart: '2026-07-31T16:00:00.000Z',
monthEnd: '2026-08-31T16:00:00.000Z',
lastSyncedAt: '2026-08-14T02:30:00.000Z',
syncStatus: 'ready',
},
}}
/>,
)
expect(screen.getByLabelText('按时交付当前值94.6%,黄色区间90%–95%')).toHaveClass('text-[#a88a00]')
expect(screen.getByText('本月按时交付率 = 本月未超时审核节点完成流程数 ÷ 本月审核节点完成流程数 × 100%')).toBeInTheDocument()
expect(screen.getByText('未超时审核节点完成 946 / 审核节点完成 1000')).toBeInTheDocument()
expect(screen.queryByText('黄色区间 · 90%–95%')).not.toBeInTheDocument()
})
it('展示首轮通过真实公式与每个作品的 V1 审核结果', () => {
render(
<CoreMetricDetail
metric={getCoreMetric('first-pass-rate')!}
firstPassPage={{
summary: {
totalUploads: 3,
totalApproved: 2,
firstPassApproved: 1,
rate: 50,
statusBreakdown: { approved: 1, revisionRequired: 1, pendingReview: 1, unknown: 0 },
readAt: '2026-08-14T02:00:00.000Z',
},
items: [
{
id: 'approved-v1',
title: '已通过作品',
description: '品牌主视觉第一版',
currentStatus: 'approved',
latestVersion: 1,
submitterName: '林一',
managerName: '陈主管',
finalReviewerName: '元泽',
workDate: '2026-08-10T00:00:00.000Z',
updatedAt: '2026-08-14T02:30:00.000Z',
firstVersionStatus: 'approved',
firstVersionSubmittedAt: '2026-08-10T02:00:00.000Z',
firstVersionCompletedAt: '2026-08-11T02:00:00.000Z',
firstVersionReviews: [{
reviewerRole: 'manager',
reviewerName: '陈主管',
decision: 'approved',
reviewedAt: '2026-08-11T01:30:00.000Z',
}],
},
{
id: 'revision-v1',
title: '首轮退修作品',
currentStatus: 'approved',
latestVersion: 2,
submitterName: '林二',
managerName: '陈主管',
finalReviewerName: '元泽',
workDate: '2026-08-11T00:00:00.000Z',
updatedAt: '2026-08-14T02:30:00.000Z',
firstVersionStatus: 'revision_required',
firstVersionSubmittedAt: '2026-08-11T02:00:00.000Z',
firstVersionCompletedAt: '2026-08-12T02:00:00.000Z',
},
{
id: 'pending-v1',
title: '评审中作品',
currentStatus: 'pending_review',
latestVersion: 1,
submitterName: '林三',
managerName: '陈主管',
finalReviewerName: '元泽',
workDate: '2026-08-12T00:00:00.000Z',
updatedAt: '2026-08-14T02:30:00.000Z',
firstVersionStatus: 'pending_review',
firstVersionSubmittedAt: '2026-08-12T02:00:00.000Z',
firstVersionCompletedAt: null,
},
],
pagination: { page: 1, pageSize: 20, total: 3, totalPages: 1 },
}}
/>,
)
expect(screen.getByRole('heading', { level: 1, name: '首轮通过' })).toBeInTheDocument()
expect(screen.getByRole('heading', { level: 2, name: '所有作品明细' })).toBeInTheDocument()
expect(screen.getByText(/全部已上传且包含 V1 的作品/)).toBeInTheDocument()
expect(screen.getByText('首轮通过率 = V1 审核通过作品数 ÷ 所有已通过作品数 × 100%')).toBeInTheDocument()
expect(screen.getByText('当前口径:1 ÷ 2 = 50%;共读取 3 个作品')).toBeInTheDocument()
expect(screen.getAllByText('首轮通过').length).toBeGreaterThan(0)
expect(screen.getAllByText('品牌主视觉第一版').length).toBeGreaterThan(0)
expect(screen.getAllByText('陈主管(主管 · 通过)').length).toBeGreaterThan(0)
expect(screen.getAllByRole('columnheader', { name: '主管' }).length).toBeGreaterThan(0)
expect(screen.getAllByRole('columnheader', { name: '终审' }).length).toBeGreaterThan(0)
expect(screen.getAllByText('首轮未通过').length).toBeGreaterThan(0)
expect(screen.getAllByText('首轮评审中').length).toBeGreaterThan(0)
expect(screen.getByText('搜索只筛选下方明细,不改变上方完整统计口径。')).toBeInTheDocument()
expect(screen.getByRole('link', { name: /打开作品过稿数据源/ })).toHaveAttribute('href', 'https://sc.jiansun.vip/work-review')
})
})