feat(platform): harden telemetry pipeline and unify Semi UI workspaces
This commit is contained in:
@@ -6,11 +6,34 @@ import indexSource from '../../index.html?raw';
|
||||
import mainSource from '../main.tsx?raw';
|
||||
|
||||
const v2Styles = readFileSync(resolve(process.cwd(), 'src/v2/styles/v2.css'), 'utf8');
|
||||
const workspaceStyles = readFileSync(resolve(process.cwd(), 'src/v2/styles/workspace.css'), 'utf8');
|
||||
const corePageSources = Object.fromEntries(['MonitorPage', 'VehiclePage', 'TrackPage', 'HistoryPage', 'StatisticsPage', 'AlertsPage', 'AccessPage', 'UsersPage', 'OperationsPage'].map((name) => [
|
||||
name,
|
||||
readFileSync(resolve(process.cwd(), `src/v2/pages/${name}.tsx`), 'utf8')
|
||||
]));
|
||||
const reconciliationSource = readFileSync(resolve(process.cwd(), 'src/v2/pages/ReconciliationCenter.tsx'), 'utf8');
|
||||
const profileSyncPanelSource = readFileSync(resolve(process.cwd(), 'src/v2/pages/VehicleProfileSyncPanel.tsx'), 'utf8');
|
||||
const sourceEvidenceSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/VehicleSourceEvidencePanel.tsx'), 'utf8');
|
||||
const mobileFilterToggleSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/MobileFilterToggle.tsx'), 'utf8');
|
||||
const segmentedTabsSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/SegmentedTabs.tsx'), 'utf8');
|
||||
const metricActionSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/MetricActionButton.tsx'), 'utf8');
|
||||
const tablePaginationSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/TablePagination.tsx'), 'utf8');
|
||||
const vehicleOptionErrorSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/VehicleOptionError.tsx'), 'utf8');
|
||||
const vehicleCandidateListSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/VehicleCandidateList.tsx'), 'utf8');
|
||||
const recoveryActionsSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/RecoveryActions.tsx'), 'utf8');
|
||||
const detailTriggerRowSource = readFileSync(resolve(process.cwd(), 'src/v2/shared/detailTriggerRow.ts'), 'utf8');
|
||||
const appShellSource = readFileSync(resolve(process.cwd(), 'src/v2/layout/AppShell.tsx'), 'utf8');
|
||||
const routeBoundarySource = readFileSync(resolve(process.cwd(), 'src/v2/routing/RouteBoundary.tsx'), 'utf8');
|
||||
const fleetMapSource = readFileSync(resolve(process.cwd(), 'src/v2/map/FleetMap.tsx'), 'utf8');
|
||||
const trackMapSource = readFileSync(resolve(process.cwd(), 'src/v2/map/TrackMap.tsx'), 'utf8');
|
||||
|
||||
describe('V2 production entry', () => {
|
||||
test('does not load the legacy Semi UI theme and global stylesheet', () => {
|
||||
test('loads the scoped production Semi theme without the retired global stylesheet', () => {
|
||||
expect(mainSource).not.toContain("./styles/global.css");
|
||||
expect(mainSource).toContain("./v2/styles/semi-theme.scss");
|
||||
expect(mainSource).toContain("./v2/styles/v2.css");
|
||||
expect(mainSource).toContain("./v2/styles/workspace.css");
|
||||
expect(mainSource).toContain("window.history.scrollRestoration = 'manual'");
|
||||
});
|
||||
|
||||
test('renders a static boot shell and recovers when the React entry never becomes ready', () => {
|
||||
@@ -26,6 +49,408 @@ describe('V2 production entry', () => {
|
||||
expect(appV2Source).toContain('window.dispatchEvent(new Event(PLATFORM_READY_EVENT))');
|
||||
});
|
||||
|
||||
test('keeps core business pages on shared Semi UI controls and page hierarchy', () => {
|
||||
for (const source of Object.values(corePageSources)) {
|
||||
expect(source).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(source).toContain('<Button');
|
||||
}
|
||||
for (const name of ['HistoryPage', 'AlertsPage', 'AccessPage', 'UsersPage', 'OperationsPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/PageHeader'");
|
||||
expect(corePageSources[name]).toContain('<PageHeader');
|
||||
}
|
||||
expect(corePageSources.StatisticsPage).not.toContain("from '../shared/PageHeader'");
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<PageHeader');
|
||||
expect(corePageSources.VehiclePage).toContain('<Select');
|
||||
expect(corePageSources.VehiclePage).toContain('<Card className="v2-record-card v2-live-card v2-live-overview"');
|
||||
expect(corePageSources.VehiclePage).toContain('<Card className="v2-single-map-card"');
|
||||
expect(corePageSources.VehiclePage).toContain('className="v2-record-section-anchor v2-record-location-anchor"');
|
||||
expect(corePageSources.VehiclePage).toContain('<Card className="v2-identity-band"');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<section className="v2-record-card');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<section className="v2-single-map-card');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<section className="v2-identity-band"');
|
||||
expect(corePageSources.VehiclePage).toContain('<SegmentedTabs');
|
||||
expect(corePageSources.VehiclePage).toContain('<Descriptions className="v2-record-descriptions"');
|
||||
expect(corePageSources.VehiclePage).toContain('<Empty image={<IconSearch size="extra-large" />} title="未找到车辆"');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<dl className="v2-record-list"');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<section className="v2-not-found"');
|
||||
expect(corePageSources.VehiclePage).toContain('v2-telemetry-protocols');
|
||||
expect(corePageSources.VehiclePage).toContain('<Table');
|
||||
expect(corePageSources.VehiclePage).toContain('className="v2-telemetry-table"');
|
||||
expect(corePageSources.VehiclePage).toContain('<List className="v2-telemetry-mobile-list"');
|
||||
expect(corePageSources.VehiclePage).toContain('<List.Item className="v2-telemetry-mobile-item"');
|
||||
expect(corePageSources.VehiclePage).toContain('<List');
|
||||
expect(corePageSources.VehiclePage).toContain('className="v2-event-list"');
|
||||
expect(corePageSources.VehiclePage).toContain('useMobileLayout');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<div className="v2-telemetry-list"');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<nav className="v2-telemetry-protocols"');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<input');
|
||||
expect(corePageSources.VehiclePage).not.toContain('<button');
|
||||
expect(corePageSources.VehiclePage).toContain("lazy(() => import('./VehicleProfileSyncPanel'))");
|
||||
expect(corePageSources.VehiclePage).toContain('<Card className="v2-profile-sync-panel v2-profile-sync-loading"');
|
||||
expect(profileSyncPanelSource).toContain('<Upload');
|
||||
expect(profileSyncPanelSource).toContain('<Card className="v2-profile-sync-panel"');
|
||||
expect(profileSyncPanelSource).not.toContain('<input');
|
||||
expect(profileSyncPanelSource).not.toContain('<section className="v2-profile-sync-panel"');
|
||||
expect(corePageSources.VehiclePage).toContain('v2-profile-sync-panel');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-vehicle-detail"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-detail-peek"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-event-strip"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Tag className={`v2-status-text');
|
||||
expect(corePageSources.MonitorPage).toContain('<Tag className="v2-monitor-live-tag"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<aside className="v2-vehicle-detail"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<aside className="v2-detail-peek"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<section className="v2-event-strip"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Table className="v2-monitor-table"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Empty className="v2-monitor-table-empty"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Spin size="small" tip="正在更新车辆实时数据…"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<table><thead><tr><th>车辆</th>');
|
||||
expect(sourceEvidenceSource).toContain("import { Button, Card, Empty, Input, Spin, Tag } from '@douyinfe/semi-ui'");
|
||||
expect(sourceEvidenceSource).toContain('<Card className={`v2-source-evidence');
|
||||
expect(sourceEvidenceSource).toContain('<Card className={`v2-source-evidence-card');
|
||||
expect(sourceEvidenceSource).toContain('<Tag className="is-recommended"');
|
||||
expect(sourceEvidenceSource).toContain('<Spin size="small"');
|
||||
expect(sourceEvidenceSource).toContain('<Empty className="v2-source-evidence-empty"');
|
||||
expect(sourceEvidenceSource).not.toContain('<article className={`v2-source-evidence-card');
|
||||
expect(sourceEvidenceSource).not.toContain('<section className={`v2-source-evidence');
|
||||
expect(corePageSources.HistoryPage).toContain('<Input');
|
||||
expect(corePageSources.HistoryPage).toContain('<Select');
|
||||
expect(corePageSources.HistoryPage).toContain('<Checkbox');
|
||||
expect(corePageSources.HistoryPage).toContain('<SideSheet');
|
||||
expect(corePageSources.HistoryPage).toContain('v2-history-column-sidesheet');
|
||||
expect(corePageSources.HistoryPage).toContain('<Card key={row.id} className={`v2-history-mobile-card');
|
||||
expect(corePageSources.HistoryPage).toContain('v2-history-trend');
|
||||
for (const surface of ['v2-export-jobs', 'v2-history-evidence', 'v2-history-metrics-card', 'v2-history-summary']) {
|
||||
expect(corePageSources.HistoryPage).toContain(`<Card className="${surface}"`);
|
||||
}
|
||||
expect(corePageSources.HistoryPage).toContain('<Card className={`v2-history-filter-card');
|
||||
expect(corePageSources.HistoryPage).toContain('<Card className={`v2-history-table-card');
|
||||
expect(corePageSources.HistoryPage).toContain('<Descriptions className="v2-history-evidence-descriptions"');
|
||||
expect(corePageSources.HistoryPage).toContain('<Descriptions className="v2-evidence-values"');
|
||||
expect(corePageSources.HistoryPage).toContain('<Card className={`v2-export-job-card');
|
||||
expect(corePageSources.HistoryPage).toContain('<Progress className="v2-export-job-progress"');
|
||||
expect(corePageSources.HistoryPage).toContain('<Empty className="v2-history-empty"');
|
||||
expect(corePageSources.HistoryPage).toContain('<Spin size="middle" tip="正在加载当前筛选范围的历史数据…"');
|
||||
expect(corePageSources.HistoryPage).not.toContain('row ? <><dl>');
|
||||
expect(corePageSources.HistoryPage).not.toContain('job) => <article');
|
||||
expect(corePageSources.HistoryPage).not.toContain('<section className="v2-history-trend"');
|
||||
expect(corePageSources.HistoryPage).not.toContain('<section className={`v2-history-table-card');
|
||||
expect(corePageSources.HistoryPage).not.toContain('<input');
|
||||
expect(corePageSources.HistoryPage).not.toContain('<button');
|
||||
expect(corePageSources.HistoryPage).toContain('className="v2-history-data-table"');
|
||||
expect(corePageSources.HistoryPage).toContain('detailTriggerRow({');
|
||||
expect(corePageSources.HistoryPage).not.toContain('<table><thead><tr><th aria-label="选择行"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Input');
|
||||
expect(corePageSources.AlertsPage).toContain('<Select');
|
||||
expect(corePageSources.AlertsPage).toContain('<TextArea');
|
||||
expect(corePageSources.AlertsPage).toContain('<Radio');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card key={event.id} className={`v2-alert-mobile-card');
|
||||
for (const surface of ['v2-alert-kpis-card', 'v2-alert-table-card']) {
|
||||
expect(corePageSources.AlertsPage).toContain(`<Card className="${surface}"`);
|
||||
}
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className={`v2-alert-inspector');
|
||||
expect(corePageSources.AlertsPage).toContain('<SideSheet\n className="v2-alert-filter-sidesheet"');
|
||||
expect(corePageSources.AlertsPage).toContain('<SideSheet\n className="v2-alert-detail-sidesheet"');
|
||||
expect(corePageSources.AlertsPage).toContain('className="v2-alert-event-table"');
|
||||
expect(corePageSources.AlertsPage).toContain('detailTriggerRow({');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<table><thead><tr><th />');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className={`v2-alert-filter-card');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<section className="v2-alert-table-card"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<aside className="v2-alert-inspector"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<select');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<textarea');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<input');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<button');
|
||||
expect(corePageSources.AlertsPage).toContain('<Descriptions className="v2-alert-descriptions"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Timeline className="v2-alert-timeline"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Empty className="v2-alert-inspector-empty"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className="v2-alert-detail-card"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className="v2-alert-detail-card v2-alert-evidence-card"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<section><h3>事件信息</h3>');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<div className="v2-alert-timeline">');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className="v2-alert-rule-list"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className="v2-alert-rule-editor"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className="v2-alert-notifications"');
|
||||
expect(corePageSources.AlertsPage).toContain('<CardGroup className="v2-alert-notification-cards"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Card className={`v2-alert-notification-card');
|
||||
expect(corePageSources.AlertsPage).toContain('<Descriptions className="v2-alert-channel-descriptions"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Empty className="v2-alert-notification-empty"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Empty className="v2-alert-empty"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Spin size="middle" tip="正在更新事件…"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<article className={item.read');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<section className="v2-alert-rule-list"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<form className="v2-alert-rule-editor"');
|
||||
expect(corePageSources.AlertsPage).not.toContain('<div className="v2-alert-notifications"');
|
||||
expect(corePageSources.AccessPage).toContain('<Input');
|
||||
expect(corePageSources.AccessPage).toContain('<Select');
|
||||
expect(corePageSources.AccessPage).toContain('<Card');
|
||||
for (const surface of ['v2-access-kpis-card-v3', 'v2-access-table-v3']) {
|
||||
expect(corePageSources.AccessPage).toContain(`<Card className="${surface}"`);
|
||||
}
|
||||
expect(corePageSources.AccessPage).toContain('<Card className={`v2-access-inspector-v3');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-detail-sidesheet"');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-governance-sidesheet"');
|
||||
expect(corePageSources.AccessPage).toContain('<Card className={`v2-access-filter-card-v3');
|
||||
expect(corePageSources.AccessPage).not.toContain('<section className="v2-access-table-v3"');
|
||||
expect(corePageSources.AccessPage).not.toContain('<aside className="v2-access-inspector-v3"');
|
||||
expect(corePageSources.AccessPage).toContain('<Card key={row.vin} className={`v2-access-mobile-card');
|
||||
expect(corePageSources.AccessPage).toContain('<Descriptions className="v2-access-inspector-summary"');
|
||||
expect(corePageSources.AccessPage).toContain('<Descriptions className="v2-access-protocol-descriptions"');
|
||||
expect(corePageSources.AccessPage).toContain('<CardGroup className="v2-access-protocol-details"');
|
||||
expect(corePageSources.AccessPage).toContain('<Empty className="v2-access-empty"');
|
||||
expect(corePageSources.AccessPage).toContain('<Spin size="middle" tip="正在更新车辆接入状态…"');
|
||||
expect(corePageSources.AccessPage).toContain('className="v2-access-semi-table"');
|
||||
expect(corePageSources.AccessPage).toContain('detailTriggerRow({');
|
||||
expect(corePageSources.AccessPage).not.toContain('<table><thead><tr><th>车辆</th>');
|
||||
expect(corePageSources.AccessPage).not.toContain('<article className={`v2-access-protocol-detail');
|
||||
expect(corePageSources.AccessPage).not.toContain('<section className="v2-access-inspector-summary"');
|
||||
expect(corePageSources.AccessPage).not.toContain('<dl>');
|
||||
expect(corePageSources.AccessPage).toContain('<Collapse');
|
||||
expect(corePageSources.AccessPage).not.toContain('<select');
|
||||
expect(corePageSources.AccessPage).not.toContain('<details');
|
||||
expect(corePageSources.AccessPage).not.toContain('<summary');
|
||||
expect(corePageSources.AccessPage).not.toContain('<button');
|
||||
expect(corePageSources.UsersPage).toContain('<Input');
|
||||
expect(corePageSources.UsersPage).not.toContain('<input');
|
||||
expect(corePageSources.UsersPage).toContain('<VehicleCandidateList');
|
||||
expect(corePageSources.UsersPage).toContain('<Avatar');
|
||||
expect(corePageSources.UsersPage).toContain('<Card');
|
||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-list"');
|
||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor"');
|
||||
expect(corePageSources.UsersPage).toContain('<List');
|
||||
expect(corePageSources.UsersPage).toContain('<List.Item');
|
||||
expect(corePageSources.UsersPage).toContain('v2-user-directory-metrics');
|
||||
expect(corePageSources.UsersPage).toContain('aria-expanded={selectedID === user.id && !creating}');
|
||||
expect(corePageSources.UsersPage).toContain('<Tabs className="v2-user-editor-tabs"');
|
||||
expect(corePageSources.UsersPage).toContain('<Tabs.TabPane');
|
||||
expect(corePageSources.UsersPage).toContain('aria-label="关闭账号详情"');
|
||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-identity-section"');
|
||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-menu-section"');
|
||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-vehicle-section"');
|
||||
expect(corePageSources.UsersPage).toContain('<Empty className="v2-user-list-empty"');
|
||||
expect(corePageSources.UsersPage).not.toContain('className="v2-user-editor-empty"');
|
||||
expect(corePageSources.UsersPage).toContain('<Empty className="v2-user-vehicle-empty"');
|
||||
expect(corePageSources.UsersPage).not.toContain('<section>');
|
||||
expect(corePageSources.UsersPage).not.toContain('<aside className="v2-user-list"');
|
||||
expect(corePageSources.UsersPage).not.toContain('<main className="v2-user-editor"');
|
||||
expect(corePageSources.UsersPage).toContain('className={`v2-user-list-row');
|
||||
expect(corePageSources.UsersPage).not.toContain('className={`v2-user-list-card');
|
||||
expect(corePageSources.UsersPage).toContain('<Collapse');
|
||||
expect(corePageSources.UsersPage).toContain('<Tag');
|
||||
expect(corePageSources.UsersPage).not.toContain('<details');
|
||||
expect(corePageSources.UsersPage).not.toContain('<summary');
|
||||
expect(corePageSources.UsersPage).not.toContain('<button');
|
||||
expect(corePageSources.OperationsPage).toContain('<Checkbox');
|
||||
expect(corePageSources.OperationsPage).toContain('<Input');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-source-diagnostic"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-ops-kpi-card"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-ops-panel v2-ops-links"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className={`v2-ops-link-card');
|
||||
expect(corePageSources.OperationsPage).toContain('<Descriptions className="v2-ops-runtime-descriptions"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Empty className="v2-ops-capacity-empty"');
|
||||
expect(corePageSources.OperationsPage).toContain('<CardGroup className="v2-ops-source-list"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className={`v2-ops-source-card');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<article key={item.name}');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<article key={source.protocol}');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<dl><div><dt>生产数据模式</dt>');
|
||||
expect(corePageSources.OperationsPage).toContain('<Empty className="v2-source-empty"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Spin size="large"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-source-summary-card"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className={`v2-source-summary-card');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-source-recommendation"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Card className="v2-source-audit"');
|
||||
expect(corePageSources.OperationsPage).toContain('className="v2-source-table"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Table');
|
||||
expect(corePageSources.OperationsPage).toContain('<SideSheet');
|
||||
expect(corePageSources.OperationsPage).toContain('v2-source-policy-sidesheet');
|
||||
expect(corePageSources.OperationsPage).toContain('className={`v2-source-mobile-card');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<table className="v2-source-table"');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<section className="v2-source-diagnostic"');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<section className="v2-ops-links"');
|
||||
expect(corePageSources.OperationsPage).not.toContain('<article><small>车辆</small>');
|
||||
expect(reconciliationSource).toContain('<Table className="v2-reconcile-table"');
|
||||
expect(reconciliationSource).toContain('detailTriggerRow({');
|
||||
expect(reconciliationSource).toContain('<Card key={item.id} className={`v2-reconcile-mobile-card');
|
||||
expect(reconciliationSource).toContain('<Empty className="v2-reconcile-empty"');
|
||||
expect(reconciliationSource).toContain('<Spin size="middle" tip="正在读取差异队列…"');
|
||||
expect(reconciliationSource).not.toContain('<table className="v2-reconcile-table"');
|
||||
expect(detailTriggerRowSource).toContain("'aria-expanded': expanded");
|
||||
expect(detailTriggerRowSource).toContain("event.key !== 'Enter' && event.key !== ' '");
|
||||
expect(corePageSources.OperationsPage).not.toContain('<section className="v2-source-audit"');
|
||||
expect(corePageSources.OperationsPage).toContain('<VehicleCandidateList');
|
||||
expect(corePageSources.TrackPage).toContain('<VehicleCandidateList');
|
||||
expect(corePageSources.StatisticsPage).toContain('<VehicleCandidateList');
|
||||
expect(corePageSources.TrackPage).toContain('<Input');
|
||||
expect(corePageSources.TrackPage).toContain('<Select');
|
||||
expect(corePageSources.TrackPage).toContain('<Slider');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className={`v2-track-query-card${queryCollapsed');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-rail-result"');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-current-card"');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-empty-state"');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-playback-dock"');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-overview-card"');
|
||||
expect(corePageSources.TrackPage).toContain('<Descriptions className="v2-track-overview-descriptions"');
|
||||
expect(corePageSources.TrackPage).toContain('<Empty className="v2-track-rail-empty"');
|
||||
expect(corePageSources.TrackPage).toContain('<List className="v2-track-evidence-list v2-track-stop-list"');
|
||||
expect(corePageSources.TrackPage).toContain('<List className="v2-track-evidence-list v2-track-event-list"');
|
||||
expect(corePageSources.TrackPage).toContain('<List.Item className="v2-track-evidence-item"');
|
||||
expect(corePageSources.TrackPage).toContain('<Empty image={<IconMapPin />} title="先选择车辆,再开始轨迹回放"');
|
||||
expect(corePageSources.TrackPage).not.toContain('<Card className="v2-track-overview-card"><header><strong>行程概览</strong><Tag color={track.sampled ? \'orange\' : \'green\'} type="light" size="small">{track.sampled ? \'地图已抽稀\' : \'完整点集\'}</Tag></header><dl>');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className="v2-track-overview-card v2-track-source-card"');
|
||||
expect(corePageSources.TrackPage).toContain('<List className="v2-track-source-list"');
|
||||
expect(corePageSources.TrackPage).toContain('<List.Item className="v2-track-source-item"');
|
||||
expect(corePageSources.TrackPage).not.toContain('<Card className="v2-track-source-item"');
|
||||
expect(corePageSources.TrackPage).toContain('<Card className={`v2-track-overview-card v2-track-quality-card');
|
||||
expect(corePageSources.TrackPage).not.toContain('<section className={`v2-track-quality-card');
|
||||
expect(corePageSources.TrackPage).not.toContain('<article key={source.protocol}');
|
||||
expect(corePageSources.TrackPage).not.toContain('<article className="v2-track-current-card"');
|
||||
expect(corePageSources.TrackPage).not.toContain('<footer className="v2-track-playback-dock"');
|
||||
expect(corePageSources.TrackPage).not.toContain('<select');
|
||||
expect(corePageSources.TrackPage).not.toContain('<input');
|
||||
expect(corePageSources.TrackPage).not.toContain('<button');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Input');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Card className="v2-mileage-query-panel"');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Card className="v2-mileage-summary"');
|
||||
expect(corePageSources.StatisticsPage).toContain('<CardGroup className="v2-mileage-summary-secondary"');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Card className="v2-mileage-summary-card');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Card key={source.protocol} className={`v2-mileage-source-card');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<section className="v2-mileage-summary"');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<article key={source.protocol}');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Card className="v2-mileage-results"');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<section className="v2-mileage-query-panel"');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<section className="v2-mileage-results"');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Tag');
|
||||
expect(corePageSources.StatisticsPage).toContain('<SideSheet');
|
||||
expect(corePageSources.StatisticsPage).toContain('v2-mileage-source-sidesheet');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('v2-mileage-source-popover');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Table className="v2-mileage-table"');
|
||||
expect(v2Styles).toContain('.v2-mileage-table.semi-table-wrapper :is(.semi-table-row-head,.semi-table-row-cell).is-plate');
|
||||
expect(v2Styles).toContain('.v2-mileage-table.semi-table-wrapper :is(.semi-table-row-head,.semi-table-row-cell).is-total');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Spin size="middle" tip="正在查询里程"');
|
||||
expect(corePageSources.StatisticsPage).toContain('<Empty className="v2-mileage-empty"');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<table className="v2-mileage-table"');
|
||||
expect(corePageSources.StatisticsPage).not.toContain('<input');
|
||||
expect(corePageSources.MonitorPage).toContain('<Input');
|
||||
expect(corePageSources.MonitorPage).toContain('<Select');
|
||||
expect(corePageSources.MonitorPage).toContain('<Modal');
|
||||
expect(corePageSources.MonitorPage).toContain('v2-monitor-qr-modal');
|
||||
expect(corePageSources.MonitorPage).not.toContain('v2-monitor-qr-backdrop');
|
||||
expect(corePageSources.MonitorPage).toContain('<TextArea');
|
||||
expect(corePageSources.MonitorPage).toContain('<ButtonGroup');
|
||||
expect(corePageSources.MonitorPage).toContain("aria-pressed={mode === 'map'}");
|
||||
expect(corePageSources.MonitorPage).toContain("aria-pressed={mode === 'list'}");
|
||||
expect(v2Styles).toContain('.v2-monitor-mode.semi-button-group > .semi-button-group-line { display: none; }');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<select');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<textarea');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<button');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-filterbar"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-kpis"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-monitor-table-panel"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<section className="v2-filterbar"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<section className="v2-kpis"');
|
||||
expect(corePageSources.MonitorPage).not.toContain('<section className="v2-monitor-table-panel"');
|
||||
expect(corePageSources.MonitorPage).toContain('<Card className="v2-monitor-mobile-card"');
|
||||
expect(reconciliationSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(reconciliationSource).toContain('<RadioGroup');
|
||||
expect(reconciliationSource).toContain('<Select');
|
||||
expect(reconciliationSource).toContain('<Card className="v2-reconcile-center"');
|
||||
expect(reconciliationSource).toContain('<Card className="v2-reconcile-kpi-card');
|
||||
expect(reconciliationSource).toContain('v2-reconcile-trend');
|
||||
expect(reconciliationSource).toContain('<Card className={`v2-reconcile-detail');
|
||||
expect(reconciliationSource).toContain('<SideSheet');
|
||||
expect(reconciliationSource).toContain('className="v2-reconcile-detail-sidesheet"');
|
||||
expect(reconciliationSource).toContain('<Card className="v2-reconcile-evidence"');
|
||||
expect(reconciliationSource).toContain("from '../shared/WorkspacePanelHeader'");
|
||||
expect(reconciliationSource).toContain('<WorkspacePanelHeader');
|
||||
expect(reconciliationSource).toContain('className="v2-reconcile-heading"');
|
||||
expect(reconciliationSource).toContain('className="v2-reconcile-detail-heading"');
|
||||
expect(reconciliationSource).not.toContain('<header className="v2-reconcile-heading"');
|
||||
expect(reconciliationSource).not.toContain('<section className="v2-reconcile-center"');
|
||||
expect(reconciliationSource).not.toContain('<aside className="v2-reconcile-detail"');
|
||||
expect(reconciliationSource).toContain('<TextArea');
|
||||
expect(sourceEvidenceSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(sourceEvidenceSource).toContain('<Input');
|
||||
expect(sourceEvidenceSource).toContain('<Button');
|
||||
expect(mobileFilterToggleSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(mobileFilterToggleSource).toContain('<Button');
|
||||
expect(segmentedTabsSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(segmentedTabsSource).toContain('role="tablist"');
|
||||
expect(segmentedTabsSource).toContain('role="tab"');
|
||||
for (const name of ['VehiclePage', 'AlertsPage', 'TrackPage', 'OperationsPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/SegmentedTabs'");
|
||||
expect(corePageSources[name]).toContain('<SegmentedTabs');
|
||||
}
|
||||
expect(corePageSources.OperationsPage).toContain('className={`v2-ops-workspace is-${workspace}`}');
|
||||
expect(corePageSources.OperationsPage).toContain('role="tabpanel"');
|
||||
expect(metricActionSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(metricActionSource).toContain('aria-pressed={active}');
|
||||
expect(tablePaginationSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(tablePaginationSource).toContain('aria-label="上一页"');
|
||||
expect(tablePaginationSource).toContain('aria-label="下一页"');
|
||||
for (const name of ['MonitorPage', 'AlertsPage', 'HistoryPage', 'AccessPage', 'StatisticsPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/TablePagination'");
|
||||
expect(corePageSources[name]).toContain('<TablePagination');
|
||||
}
|
||||
expect(reconciliationSource).toContain("from '../shared/TablePagination'");
|
||||
expect(reconciliationSource).toContain('<TablePagination');
|
||||
expect(vehicleOptionErrorSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(vehicleOptionErrorSource).toContain('<Button');
|
||||
expect(vehicleCandidateListSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(vehicleCandidateListSource).toContain("from './VehicleOptionError'");
|
||||
expect(vehicleCandidateListSource).toContain('<VehicleOptionError');
|
||||
expect(vehicleCandidateListSource).toContain('role="listbox"');
|
||||
expect(vehicleCandidateListSource).toContain('role="option"');
|
||||
expect(recoveryActionsSource).toContain("from '@douyinfe/semi-ui'");
|
||||
expect(recoveryActionsSource).toContain('<Button');
|
||||
expect(routeBoundarySource).toContain("from '../shared/RecoveryActions'");
|
||||
expect(routeBoundarySource).toContain('<RecoveryActions');
|
||||
expect(routeBoundarySource).not.toContain('<button');
|
||||
for (const source of [fleetMapSource, trackMapSource]) {
|
||||
expect(source).toContain("from '../shared/RecoveryActions'");
|
||||
expect(source).toContain('<MapRetryAction');
|
||||
expect(source).not.toContain('><IconRefresh />重新加载地图</button>');
|
||||
}
|
||||
for (const name of ['AlertsPage', 'AccessPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/MetricActionButton'");
|
||||
expect(corePageSources[name]).toContain('<MetricActionButton');
|
||||
}
|
||||
expect(corePageSources.HistoryPage).toContain('<Tag className="v2-history-metric-tag"');
|
||||
expect(corePageSources.AlertsPage).toContain('<Tag className={`v2-alert-severity');
|
||||
expect(corePageSources.AlertsPage).toContain('<Tag className={`v2-alert-status');
|
||||
expect(corePageSources.AlertsPage).toContain('className="v2-alert-inspector-heading"');
|
||||
expect(corePageSources.AlertsPage).toContain('className="v2-alert-rule-list-heading"');
|
||||
expect(corePageSources.AlertsPage).toContain('className="v2-alert-rule-editor-heading"');
|
||||
expect(corePageSources.AlertsPage).toContain('variant="filled"');
|
||||
expect(corePageSources.AccessPage).toContain('<Tag className="v2-access-connection-tag"');
|
||||
expect(corePageSources.OperationsPage).toContain('<Tag className={`v2-ops-health-tag');
|
||||
expect(reconciliationSource).toContain('<Tag className={`v2-reconcile-severity');
|
||||
expect(reconciliationSource).toContain('<Tag className={`v2-reconcile-status');
|
||||
expect(v2Styles).toContain('.v2-track-rail-expand { z-index: 21; top: auto; bottom: calc(132px + env(safe-area-inset-bottom));');
|
||||
expect(v2Styles).toContain('.v2-track-stage:has(.v2-track-current-card) .v2-track-rail-expand { bottom: calc(248px + env(safe-area-inset-bottom));');
|
||||
expect(v2Styles).toContain('grid-template-rows: minmax(0, 1fr);');
|
||||
expect(appShellSource).toContain("section === 'tracks' ? ' is-track-workspace' : ''");
|
||||
expect(corePageSources.TrackPage).toContain("monitorReturn ? ' has-monitor-return' : ''");
|
||||
expect(v2Styles).toContain('.v2-track-page.has-monitor-return { grid-template-rows: auto minmax(0, 1fr); }');
|
||||
expect(v2Styles).toContain('.v2-content.is-track-workspace { min-height: 0; overflow: hidden; }');
|
||||
expect(workspaceStyles).toContain('.v2-workspace-panel-header.is-inverted > .v2-workspace-panel-copy > h5.semi-typography');
|
||||
expect(workspaceStyles).toContain('color: #f8fbff;');
|
||||
expect(v2Styles).toContain('.v2-track-current-card > .semi-card-body > div strong { margin-top: 4px; color: var(--track-overlay-text);');
|
||||
expect(v2Styles).toContain('.v2-track-current-card.semi-card { top: auto; right: 8px; bottom: 126px; left: 8px; width: auto; height: auto;');
|
||||
for (const name of ['HistoryPage', 'StatisticsPage', 'AlertsPage', 'AccessPage']) {
|
||||
expect(corePageSources[name]).toContain("from '../shared/MobileFilterToggle'");
|
||||
expect(corePageSources[name]).toContain('<MobileFilterToggle');
|
||||
expect(corePageSources[name]).not.toContain('<button type="button" className="v2-mobile-filter-toggle"');
|
||||
}
|
||||
});
|
||||
|
||||
test('keeps the shared desktop and mobile application shell on Semi UI navigation primitives', () => {
|
||||
expect(appShellSource).toContain('<Layout className="v2-shell">');
|
||||
expect(appShellSource).toContain('<Nav className="v2-navigation"');
|
||||
expect(appShellSource).toContain('<SideSheet className="v2-mobile-more-sidesheet"');
|
||||
expect(appShellSource).toContain('<Modal className="v2-password-modal"');
|
||||
expect(appShellSource).not.toContain('v2-mobile-more-backdrop');
|
||||
expect(appShellSource).not.toContain('v2-mobile-more-sheet');
|
||||
});
|
||||
|
||||
test('applies rendering containment to off-screen vehicle items instead of the visible scroller', () => {
|
||||
const ruleBody = (selector: string) => {
|
||||
const start = v2Styles.indexOf(`${selector} {`);
|
||||
@@ -35,8 +460,8 @@ describe('V2 production entry', () => {
|
||||
return v2Styles.slice(start, end);
|
||||
};
|
||||
const scrollRule = ruleBody('.v2-vehicle-scroll');
|
||||
const rowRule = ruleBody('.v2-vehicle-row');
|
||||
const mobileCardRule = ruleBody('.v2-monitor-mobile-cards > article');
|
||||
const rowRule = ruleBody('.v2-vehicle-row.semi-button');
|
||||
const mobileCardRule = ruleBody('.v2-monitor-mobile-cards > .v2-monitor-mobile-card.semi-card');
|
||||
|
||||
expect(scrollRule).not.toContain('content-visibility');
|
||||
expect(rowRule).toContain('content-visibility: auto');
|
||||
|
||||
Reference in New Issue
Block a user