Files
X-Financial/web/tests/documents-center-status-filter.test.mjs

387 lines
22 KiB
JavaScript
Raw Normal View History

import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
import { fileURLToPath } from 'node:url'
const documentsCenterView = readFileSync(
fileURLToPath(new URL('../src/views/DocumentsCenterView.vue', import.meta.url)),
'utf8'
)
const documentsCenterViewModel = readFileSync(
fileURLToPath(new URL('../src/utils/documentCenterViewModel.js', import.meta.url)),
'utf8'
)
const documentsCenterLogic = `${documentsCenterView}\n${documentsCenterViewModel}`
const documentsCenterStyles = readFileSync(
fileURLToPath(new URL('../src/assets/styles/views/documents-center-view.css', import.meta.url)),
'utf8'
)
const documentListSharedStyles = readFileSync(
fileURLToPath(new URL('../src/assets/styles/components/document-list-shared.css', import.meta.url)),
'utf8'
)
const tableLoadingState = readFileSync(
fileURLToPath(new URL('../src/components/shared/TableLoadingState.vue', import.meta.url)),
'utf8'
)
const reimbursementService = readFileSync(
fileURLToPath(new URL('../src/services/reimbursements.js', import.meta.url)),
'utf8'
)
const requestsComposable = readFileSync(
fileURLToPath(new URL('../src/composables/useRequests.js', import.meta.url)),
'utf8'
)
test('documents center keeps only the top scope tabs and renders risk level as a dropdown filter', () => {
assert.match(documentsCenterView, /<nav class="status-tabs document-scope-tabs"/)
assert.doesNotMatch(documentsCenterView, /<nav class="status-tabs document-state-tabs"/)
assert.match(documentsCenterView, /class="document-status-filter"[\s\S]*class="document-filter status-dropdown-filter"/)
assert.match(
documentsCenterView,
/<div class="filter-set">[\s\S]*<div class="list-search">[\s\S]*<div class="document-status-filter"[\s\S]*<div v-if="showDocumentTypeFilter" class="document-filter">/
)
assert.match(documentsCenterView, /v-for="option in statusFilterOptions"/)
assert.match(documentsCenterView, /@click="selectStatusTab\(option\.value\)"/)
assert.match(documentsCenterView, /aria-label="风险等级"/)
})
test('documents center loading state uses a compact spinner instead of light band progress', () => {
assert.match(documentsCenterView, /<TableLoadingState[\s\S]*title="单据数据同步中"[\s\S]*floating/)
assert.match(tableLoadingState, /class="table-loading-spinner"/)
assert.match(tableLoadingState, /@keyframes table-loading-spin/)
assert.match(tableLoadingState, /\.table-loading-card \{[\s\S]*width: min\(420px, 100%\);[\s\S]*display: inline-flex;/)
assert.match(tableLoadingState, /\.table-loading-spinner \{[\s\S]*border-top-color: var\(--theme-primary-active/)
assert.match(tableLoadingState, /@media \(prefers-reduced-motion: reduce\) \{[\s\S]*animation: none;/)
assert.doesNotMatch(tableLoadingState, /FloatingLightBandWindow/)
})
test('documents center top tabs start from all and show document category labels', () => {
assert.match(documentsCenterLogic, /const DOCUMENT_SCOPE_ALL = '全部'/)
assert.match(documentsCenterLogic, /const DOCUMENT_SCOPE_APPLICATION = '申请单'/)
assert.match(documentsCenterLogic, /const DOCUMENT_SCOPE_REIMBURSEMENT = '报销单'/)
assert.match(documentsCenterLogic, /const DOCUMENT_SCOPE_REVIEW = '审核单'/)
assert.match(documentsCenterLogic, /const DOCUMENT_SCOPE_ARCHIVE = '归档'/)
assert.match(documentsCenterView, /const initialScopeTab = resolveInitialScopeTab\(\)/)
assert.match(documentsCenterView, /const activeScopeTab = ref\(initialScopeTab\)/)
assert.match(
documentsCenterView,
/function resolveInitialScopeTab\(\) \{[\s\S]*readDocumentCenterQueryText\('dc_scope'\)[\s\S]*return readDocumentScope\(DOCUMENT_SCOPE_ALL, scopeTabs\)/
)
assert.match(
documentsCenterLogic,
/const scopeTabs = \[[\s\S]*DOCUMENT_SCOPE_ALL[\s\S]*DOCUMENT_SCOPE_APPLICATION[\s\S]*DOCUMENT_SCOPE_REIMBURSEMENT[\s\S]*DOCUMENT_SCOPE_REVIEW[\s\S]*DOCUMENT_SCOPE_ARCHIVE[\s\S]*\]/
)
})
test('documents center persists pagination and filters in route query for detail return', () => {
assert.match(documentsCenterView, /import \{ useRoute, useRouter \} from 'vue-router'/)
assert.match(documentsCenterLogic, /const DOCUMENT_CENTER_QUERY_KEYS = new Set\(/)
assert.match(documentsCenterLogic, /'dc_page'/)
assert.match(documentsCenterLogic, /'dc_page_size'/)
assert.match(documentsCenterView, /const currentPage = ref\(readDocumentCenterQueryNumber\('dc_page', 1\)\)/)
assert.match(documentsCenterView, /const pageSize = ref\(resolveInitialPageSize\(\)\)/)
assert.match(
documentsCenterView,
/function buildDocumentCenterRouteQuery\(\) \{[\s\S]*nextQuery\.dc_page = String\(currentPage\.value\)[\s\S]*nextQuery\.dc_page_size = String\(pageSize\.value\)/
)
assert.match(
documentsCenterView,
/watch\(\s*\[currentPage, pageSize, activeScopeTab, activeStatusTab, activeDocumentType, activeScene, listKeyword, appliedStart, appliedEnd\],[\s\S]*router\.replace\(\{ name: 'app-documents', query: nextQuery \}\)/
)
})
test('documents center category tabs map to the intended row sources', () => {
assert.match(documentsCenterView, /excludeArchivedDocumentRows/)
assert.match(documentsCenterView, /approvalRows\.value = excludeArchivedDocumentRows/)
assert.match(documentsCenterView, /const nonArchivedRows = computed\(\(\) => mergeDocumentRows\(\[\.\.\.ownedRows\.value, \.\.\.approvalRows\.value\]\)\)/)
assert.match(documentsCenterLogic, /import \{ sortDocumentRowsByLatestTime \} from '\.\/documentCenterSort\.js'/)
assert.match(documentsCenterLogic, /activeScopeTab !== DOCUMENT_SCOPE_ARCHIVE && isArchivedDocumentRow\(row\)/)
assert.match(
documentsCenterView,
/activeScopeTab\.value === DOCUMENT_SCOPE_ALL[\s\S]*return nonArchivedRows\.value/
)
assert.match(
documentsCenterView,
/activeScopeTab\.value === DOCUMENT_SCOPE_APPLICATION[\s\S]*return applicationScopeRows\.value/
)
assert.match(
documentsCenterView,
/activeScopeTab\.value === DOCUMENT_SCOPE_REIMBURSEMENT[\s\S]*ownedRows\.value\.filter/
)
assert.match(
documentsCenterView,
/activeScopeTab\.value === DOCUMENT_SCOPE_REVIEW[\s\S]*return approvalRows\.value/
)
assert.match(
documentsCenterView,
/activeScopeTab\.value === DOCUMENT_SCOPE_ARCHIVE[\s\S]*return archiveRows\.value/
)
assert.match(documentsCenterView, /return nonArchivedRows\.value/)
})
2026-06-03 16:52:49 +08:00
test('documents center sorts every filtered scope by latest document time before pagination', () => {
assert.match(
documentsCenterLogic,
/return sortDocumentRowsByLatestTime\(\(rows \|\| \[\]\)\.filter\(\(row\) => \{[\s\S]*matchesKeyword && matchesDocumentType && matchesScene && matchesRiskLevel && matchesDateRange[\s\S]*\}\)\)/
2026-06-03 16:52:49 +08:00
)
assert.match(
documentsCenterLogic,
2026-06-03 16:52:49 +08:00
/const createdSortTime = resolveDocumentSortTime\(createdAtSource\)[\s\S]*const updatedSortTime = resolveDocumentSortTime\(updatedAtSource\)/
)
assert.match(
documentsCenterLogic,
2026-06-03 16:52:49 +08:00
/createdSortTime,[\s\S]*updatedSortTime,[\s\S]*sortTime: Math\.max\(createdSortTime, updatedSortTime\)/
)
assert.match(documentsCenterLogic, /return sortDocumentRowsByLatestTime\(Array\.from\(rowMap\.values\(\)\)\)/)
assert.doesNotMatch(documentsCenterLogic, /right\.sortTime - left\.sortTime/)
2026-06-03 16:52:49 +08:00
})
test('documents center preserves application document type from mapped requests', () => {
assert.match(
documentsCenterLogic,
/const documentTypeCode = normalized\.documentTypeCode \|\| DOCUMENT_TYPE_REIMBURSEMENT/
)
assert.match(
documentsCenterLogic,
/documentTypeCode === DOCUMENT_TYPE_APPLICATION \? '申请单' : '报销单'/
)
assert.doesNotMatch(
documentsCenterLogic,
/documentTypeCode:\s*DOCUMENT_TYPE_REIMBURSEMENT,[\s\S]*documentTypeLabel:\s*'报销单'/
)
})
test('documents center refresh token reloads supporting approval and archive rows', () => {
assert.match(documentsCenterView, /refreshToken:\s*\{\s*type:\s*Number,\s*default:\s*0\s*\}/)
assert.match(
documentsCenterView,
/watch\(\s*\(\) => props\.refreshToken,[\s\S]*if \(token && token !== previousToken\) \{[\s\S]*void loadSupportingRows\(\)/
)
assert.match(documentsCenterView, /function reloadAll\(\) \{[\s\S]*emit\('reload'\)[\s\S]*void loadSupportingRows\(\)/)
})
test('documents center fetches every paginated claim page for admin-scale lists', () => {
assert.match(reimbursementService, /export function fetchAllExpenseClaims/)
assert.match(reimbursementService, /async function fetchAllExpenseClaimPages/)
assert.match(reimbursementService, /payload\.has_next/)
assert.match(requestsComposable, /import \{ fetchAllExpenseClaims \} from '\.\.\/services\/reimbursements\.js'/)
assert.match(requestsComposable, /const payload = await fetchAllExpenseClaims\(\)/)
assert.match(documentsCenterView, /fetchAllApprovalExpenseClaims/)
assert.match(documentsCenterView, /fetchAllArchivedExpenseClaims/)
assert.doesNotMatch(documentsCenterView, /REIMBURSEMENT_LIST_PREVIEW_PARAMS/)
})
test('documents center list shows created time and conditional stay time columns', () => {
assert.match(documentsCenterLogic, /import \{[\s\S]*formatDocumentListTime[\s\S]*resolveDocumentStayTimeDisplay[\s\S]*\} from '\.\/documentCenterTime\.js'/)
assert.match(documentsCenterView, /<col class="col-created">/)
assert.match(documentsCenterView, /<col v-if="showStayTimeColumn" class="col-stay">/)
assert.match(documentsCenterView, /<col class="col-initiator">/)
assert.match(documentsCenterView, /<th>单号<\/th>[\s\S]*<th>创建时间<\/th>[\s\S]*<th v-if="showStayTimeColumn">停留时间<\/th>/)
assert.match(documentsCenterView, /<th>费用场景<\/th>[\s\S]*<th>发起人<\/th>[\s\S]*<th>事项<\/th>/)
assert.match(documentsCenterView, /<td data-label="创建时间">\{\{ row\.createdAtDisplay \}\}<\/td>/)
assert.match(documentsCenterView, /<td v-if="showStayTimeColumn" data-label="停留时间">\{\{ row\.stayTimeDisplay \}\}<\/td>/)
assert.match(documentsCenterView, /<td data-label="发起人">\{\{ row\.initiatorName \}\}<\/td>/)
assert.match(
documentsCenterView,
/const showStayTimeColumn = computed\(\(\) =>[\s\S]*DOCUMENT_SCOPE_APPLICATION[\s\S]*DOCUMENT_SCOPE_REVIEW/
)
assert.match(documentsCenterLogic, /createdAtDisplay: formatDocumentListTime\(createdAtSource\)/)
assert.match(documentsCenterLogic, /stayTimeDisplay: resolveDocumentStayTimeDisplay\(normalized\)/)
assert.match(documentsCenterLogic, /initiatorName,/)
assert.match(documentsCenterView, /row\.initiatorName/)
})
test('documents center action buttons are scoped to application and reimbursement tabs', () => {
assert.match(documentsCenterView, /v-if="showToolbarActions" class="document-actions"/)
assert.match(
documentsCenterView,
/const showCreateDocumentActions = computed\(\(\) =>[\s\S]*DOCUMENT_SCOPE_APPLICATION[\s\S]*DOCUMENT_SCOPE_REIMBURSEMENT/
)
assert.match(
documentsCenterView,
/v-if="activeScopeTab === DOCUMENT_SCOPE_APPLICATION"[\s\S]*@click="emit\('create-application'\)"[\s\S]*发起申请/
)
assert.match(
documentsCenterView,
/v-if="activeScopeTab === DOCUMENT_SCOPE_REIMBURSEMENT"[\s\S]*@click="emit\('create-request'\)"[\s\S]*发起报销/
)
assert.doesNotMatch(documentsCenterView, /create-request-btn secondary/)
})
test('documents center category tabs render bubble counts for new documents', () => {
assert.match(documentsCenterView, /readViewedDocumentKeys/)
assert.match(documentsCenterView, /const viewedDocumentKeys = ref\(readViewedDocumentKeys\(\)\)/)
assert.match(documentsCenterView, /v-for="tab in scopeTabItems"/)
assert.match(documentsCenterView, /<span class="scope-tab-label">/)
assert.match(documentsCenterView, /<span v-if="tab\.badgeCount > 0" class="scope-tab-badge"/)
assert.match(documentsCenterView, /tab\.badgeCount > 99 \? '99\+' : tab\.badgeCount/)
assert.match(documentsCenterView, /const scopeNewCountMap = computed\(\(\) => \(\{/)
assert.match(documentsCenterView, /\[DOCUMENT_SCOPE_ALL\]: countNewDocuments\(nonArchivedRows\.value, viewedDocumentKeys\.value\)/)
assert.match(
documentsCenterView,
/const applicationScopeRows = computed\(\(\) => prepareApplicationScopeRows\(ownedRows\.value\)\)/
)
assert.match(
documentsCenterView,
/\[DOCUMENT_SCOPE_APPLICATION\]: countNewDocuments\(filterApplicationScopeNewRows\(applicationScopeRows\.value\), viewedDocumentKeys\.value\)/
)
assert.match(
documentsCenterView,
/\[DOCUMENT_SCOPE_REIMBURSEMENT\]: countNewDocuments\(ownedRows\.value\.filter\(\(row\) => row\.documentTypeCode === DOCUMENT_TYPE_REIMBURSEMENT\), viewedDocumentKeys\.value\)/
)
assert.match(documentsCenterView, /\[DOCUMENT_SCOPE_REVIEW\]: countNewDocuments\(approvalRows\.value, viewedDocumentKeys\.value\)/)
assert.match(documentsCenterView, /\[DOCUMENT_SCOPE_ARCHIVE\]: countNewDocuments\(archiveRows\.value, viewedDocumentKeys\.value\)/)
assert.match(
documentsCenterView,
/const scopeTabItems = computed\(\(\) =>[\s\S]*badgeCount: scopeNewCountMap\.value\[tab\] \|\| 0/
)
const scopeTabBadgeBlock = documentListSharedStyles.match(/\.scope-tab-badge\s*\{[^}]*\}/)?.[0] || ''
assert.match(documentListSharedStyles, /\.scope-tab-label\s*\{[\s\S]*align-items:\s*flex-start;[\s\S]*gap:\s*4px;/)
assert.match(scopeTabBadgeBlock, /position:\s*static;/)
assert.match(scopeTabBadgeBlock, /height:\s*14px;/)
assert.match(scopeTabBadgeBlock, /margin-top:\s*-5px;/)
assert.doesNotMatch(scopeTabBadgeBlock, /position:\s*absolute;/)
})
test('documents center can mark all unread documents as read from toolbar', () => {
assert.match(documentsCenterView, /markDocumentsViewed/)
assert.match(documentsCenterView, /patchNotificationStates/)
assert.match(documentsCenterView, /buildDocumentsViewedStatePatches/)
assert.match(documentsCenterView, /mergeNotificationStatesIntoViewedDocumentKeys/)
assert.match(
documentsCenterView,
/const allReadableDocumentRows = computed\(\(\) => \[[\s\S]*nonArchivedRows\.value[\s\S]*filterApplicationScopeNewRows\(applicationScopeRows\.value\)[\s\S]*approvalRows\.value/
)
assert.match(documentsCenterView, /const totalNewDocumentCount = computed\(\(\) => countNewDocuments\(allReadableDocumentRows\.value, viewedDocumentKeys\.value\)\)/)
assert.match(documentsCenterView, /const showToolbarActions = computed\(\(\) => showCreateDocumentActions\.value \|\| totalNewDocumentCount\.value > 0\)/)
assert.match(
documentsCenterView,
/<button[\s\S]*v-if="totalNewDocumentCount > 0"[\s\S]*class="mark-read-btn"[\s\S]*@click="markAllDocumentsRead"[\s\S]*一键已读/
)
assert.match(
documentsCenterView,
/function markAllDocumentsRead\(\) \{[\s\S]*viewedDocumentKeys\.value = markDocumentsViewed\(allReadableDocumentRows\.value, viewedDocumentKeys\.value\)/
)
assert.match(
documentsCenterView,
/function markAllDocumentsRead\(\) \{[\s\S]*const viewedPatches = buildDocumentsViewedStatePatches\(allReadableDocumentRows\.value, viewedDocumentKeys\.value\)[\s\S]*syncDocumentViewedPatches\(viewedPatches\)/
)
assert.match(
documentsCenterView,
/function resolveLiveDocumentRow\(row\) \{[\s\S]*isNewDocument: isNewDocument\(row, viewedDocumentKeys\.value\)[\s\S]*const visibleRows = computed\(\(\) => \{[\s\S]*\.map\(resolveLiveDocumentRow\)/
)
assert.match(documentListSharedStyles, /\.mark-read-btn\s*\{[\s\S]*border:\s*1px solid #fecaca;/)
})
test('documents center rows show NEW marker until the row is opened', () => {
assert.match(documentsCenterView, /<span v-if="row\.isNewDocument" class="new-document-badge">NEW<\/span>/)
assert.match(documentsCenterLogic, /isNewDocument: archived\s*\?\s*false\s*:\s*isNewDocument\(/)
assert.match(documentsCenterView, /buildDocumentViewedStatePatch\(row\)/)
assert.match(
documentsCenterView,
/function openDocument\(row\) \{[\s\S]*writeDocumentScope\(activeScopeTab\.value, scopeTabs\)[\s\S]*viewedDocumentKeys\.value = markDocumentViewed\(row, viewedDocumentKeys\.value\)[\s\S]*syncDocumentViewedPatches\(\[viewedPatch\]\)[\s\S]*emit\('open-document', row\.rawRequest \|\| row\)/
)
assert.match(documentsCenterStyles, /\.new-document-badge\s*\{[\s\S]*background:\s*#fff5f5;/)
assert.match(documentsCenterStyles, /\.new-document-badge\s*\{[\s\S]*border:\s*1px solid #fecaca;/)
assert.match(documentsCenterStyles, /\.new-document-badge::before\s*\{[\s\S]*background:\s*#ef4444;/)
assert.doesNotMatch(documentsCenterStyles, /newDocumentPulse/)
})
test('documents center empty states follow theme tone across all scope tabs', () => {
const emptyStateBlock = documentsCenterLogic.match(/function buildDocumentCenterEmptyState\(options = \{\}\) \{[\s\S]*?\n\}/)?.[0] || ''
assert.match(emptyStateBlock, /eyebrow: '申请单'[\s\S]*tone: 'theme'/)
assert.match(emptyStateBlock, /title: filtered \? '没有符合当前条件的单据'[\s\S]*tone: 'theme'/)
assert.doesNotMatch(emptyStateBlock, /tone:\s*'emerald'/)
assert.doesNotMatch(emptyStateBlock, /tone:\s*'sky'/)
assert.doesNotMatch(emptyStateBlock, /tone:\s*'slate'/)
assert.doesNotMatch(emptyStateBlock, /tone:\s*'amber'/)
})
test('documents center empty states do not render small action buttons', () => {
const emptyStateBlock = documentsCenterLogic.match(/function buildDocumentCenterEmptyState\(options = \{\}\) \{[\s\S]*?\n\}/)?.[0] || ''
assert.match(emptyStateBlock, /actionLabel:\s*''/)
assert.match(emptyStateBlock, /actionIcon:\s*''/)
assert.doesNotMatch(emptyStateBlock, /actionLabel:\s*filtered/)
assert.doesNotMatch(emptyStateBlock, /actionIcon:\s*filtered/)
assert.doesNotMatch(emptyStateBlock, /actionLabel:\s*'发起申请'/)
assert.doesNotMatch(emptyStateBlock, /actionLabel:\s*'发起报销'/)
assert.doesNotMatch(emptyStateBlock, /actionLabel:\s*'清空筛选'/)
})
test('documents center switches filter conditions by category tab', () => {
assert.match(documentsCenterLogic, /const FILTER_CONFIG_BY_SCOPE = \{/)
assert.match(
documentsCenterLogic,
/\[DOCUMENT_SCOPE_ALL\]: \{[\s\S]*sceneFallbackLabel: '单据场景'[\s\S]*statusTitle: '风险等级'[\s\S]*statusTabs: riskLevelTabs[\s\S]*showDocumentType: true/
)
assert.match(
documentsCenterLogic,
/\[DOCUMENT_SCOPE_APPLICATION\]: \{[\s\S]*sceneFallbackLabel: '申请场景'[\s\S]*statusTitle: '风险等级'[\s\S]*statusTabs: riskLevelTabs[\s\S]*showDocumentType: false/
)
assert.match(
documentsCenterLogic,
/\[DOCUMENT_SCOPE_REIMBURSEMENT\]: \{[\s\S]*statusTitle: '风险等级'[\s\S]*statusTabs: riskLevelTabs[\s\S]*showDocumentType: false/
)
assert.match(
documentsCenterLogic,
/\[DOCUMENT_SCOPE_REVIEW\]: \{[\s\S]*sceneFallbackLabel: '审核场景'[\s\S]*statusTitle: '风险等级'[\s\S]*statusTabs: riskLevelTabs/
)
assert.match(
documentsCenterLogic,
/\[DOCUMENT_SCOPE_ARCHIVE\]: \{[\s\S]*dateLabel: '归档时间'[\s\S]*statusTitle: '风险等级'[\s\S]*statusTabs: riskLevelTabs/
)
assert.match(documentsCenterView, /v-if="showDocumentTypeFilter" class="document-filter"/)
assert.match(documentsCenterView, /:placeholder="activeFilterConfig\.searchPlaceholder"/)
assert.match(documentsCenterView, /class="document-status-filter" :aria-label="activeFilterConfig\.statusTitle"/)
assert.doesNotMatch(documentsCenterView, /class="status-filter-label"/)
assert.match(
documentsCenterView,
/watch\(activeFilterConfig, \(\) => \{[\s\S]*openFilterKey\.value = ''[\s\S]*datePopover\.value = false/
)
assert.match(documentsCenterView, /<EnterprisePagination[\s\S]*:page-size="pageSize"[\s\S]*:page-size-options="pageSizeOptions"/)
assert.doesNotMatch(documentsCenterView, /pageSizeOpen/)
})
test('documents center risk dropdown derives labels and closes after selection', () => {
assert.match(documentsCenterLogic, /const riskLevelTabs = \['全部', '高风险', '中风险', '低风险', '无风险'\]/)
assert.match(documentsCenterView, /const statusFilterOptions = computed\(\(\) =>/)
assert.match(documentsCenterView, /activeFilterConfig\.value\.statusTabs\.map/)
assert.match(documentsCenterView, /label: tab === '全部' \? '全部风险' : tab/)
assert.match(documentsCenterView, /const statusFilterLabel = computed\(\(\) =>/)
assert.match(
documentsCenterView,
/function selectStatusTab\(value\) \{[\s\S]*activeStatusTab\.value = value[\s\S]*openFilterKey\.value = ''[\s\S]*\}/
)
})
test('documents center list renders risk level tags instead of status tags', () => {
assert.match(documentsCenterView, /<th>风险等级<\/th>/)
assert.match(documentsCenterView, /<td data-label="风险等级">[\s\S]*class="risk-level-tags"[\s\S]*v-for="tag in row\.riskTags"/)
assert.match(documentsCenterLogic, /import \{ countClaimRisks, resolveArchiveRiskTone \} from '\.\/archiveCenterListFilters\.js'/)
assert.match(documentsCenterLogic, /function buildDocumentRiskMeta\(row, currentUser = null\) \{[\s\S]*countClaimRisks\(riskFlags, riskSummary, viewerOptions\)/)
assert.match(documentsCenterLogic, /riskTone: riskMeta\.tone,[\s\S]*riskLabel: riskMeta\.label,[\s\S]*riskCount: riskMeta\.count,[\s\S]*riskTags: riskMeta\.tags/)
assert.match(documentsCenterLogic, /function matchesRiskLevelTab\(row, tab, activeScopeTab = DOCUMENT_SCOPE_ALL\) \{[\s\S]*tab === '高风险'[\s\S]*row\.riskTone === 'high'/)
assert.match(documentListSharedStyles, /\.risk-level-tags\s*\{[\s\S]*display:\s*inline-flex;/)
assert.match(documentListSharedStyles, /\.risk-level-tag\.high\s*\{[\s\S]*background:\s*#fef2f2;/)
assert.doesNotMatch(documentsCenterView, /<td data-label="状态"><span class="status-tag"/)
})
test('documents center status dropdown uses compact filter styling', () => {
assert.match(documentsCenterStyles, /\.documents-list\s*\{[\s\S]*grid-template-rows:\s*auto auto minmax\(0,\s*1fr\) auto;/)
assert.match(documentListSharedStyles, /\.status-tabs button\s*\{[\s\S]*display:\s*inline-flex;/)
assert.match(documentListSharedStyles, /\.scope-tab-badge\s*\{[\s\S]*border-radius:\s*999px;/)
assert.match(documentListSharedStyles, /min-width:\s*1420px;/)
assert.match(documentsCenterStyles, /\.col-created\s*\{\s*width:\s*10%;\s*\}/)
assert.match(documentsCenterStyles, /\.col-stay\s*\{\s*width:\s*9%;\s*\}/)
assert.match(documentsCenterStyles, /\.col-initiator\s*\{\s*width:\s*8%;\s*\}/)
assert.match(documentListSharedStyles, /\.document-status-filter\s*\{[\s\S]*display:\s*inline-flex;/)
assert.match(documentListSharedStyles, /\.document-status-filter\s*\{[\s\S]*min-height:\s*38px;/)
assert.match(documentListSharedStyles, /\.status-dropdown-filter,\s*\.status-filter-trigger,\s*\.status-filter-menu\s*\{[\s\S]*min-width:\s*154px;/)
assert.doesNotMatch(documentsCenterStyles, /\.document-state-tabs\s*\{/)
assert.doesNotMatch(documentsCenterStyles, /\.document-status-filter\s*\{[^}]*margin-top:/)
})