niceeval 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INDEX.md +23 -23
- package/README.zh.md +6 -6
- package/dist/agents/types.d.ts +69 -7
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +57 -3
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +32 -24
- package/dist/report/aggregate.js +158 -50
- package/dist/report/built-in/index.d.ts +2 -0
- package/dist/report/built-in/index.js +8 -0
- package/dist/report/components.d.ts +93 -160
- package/dist/report/components.js +377 -114
- package/dist/report/compute.d.ts +87 -81
- package/dist/report/compute.js +597 -417
- package/dist/report/flag.d.ts +32 -6
- package/dist/report/flag.js +92 -4
- package/dist/report/format.d.ts +19 -11
- package/dist/report/format.js +30 -13
- package/dist/report/index.d.ts +16 -16
- package/dist/report/index.js +20 -21
- package/dist/report/load.js +3 -2
- package/dist/report/locale.d.ts +57 -33
- package/dist/report/locale.js +122 -56
- package/dist/report/metrics.d.ts +23 -4
- package/dist/report/metrics.js +110 -25
- package/dist/report/primitives.d.ts +48 -15
- package/dist/report/primitives.js +135 -26
- package/dist/report/react/AttemptList.d.ts +9 -7
- package/dist/report/react/AttemptList.js +17 -10
- package/dist/report/react/DeltaTable.js +19 -18
- package/dist/report/react/EvalList.d.ts +4 -4
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +10 -0
- package/dist/report/react/ExperimentComparison.js +12 -0
- package/dist/report/react/ExperimentList.d.ts +4 -3
- package/dist/report/react/ExperimentList.js +17 -18
- package/dist/report/react/MetricBars.js +5 -4
- package/dist/report/react/MetricLine.js +12 -5
- package/dist/report/react/MetricMatrix.js +1 -1
- package/dist/report/react/MetricScatter.js +59 -28
- package/dist/report/react/MetricTable.js +2 -12
- package/dist/report/react/ScopeSummary.d.ts +10 -0
- package/dist/report/react/ScopeSummary.js +17 -0
- package/dist/report/react/Scoreboard.js +6 -6
- package/dist/report/react/cell.js +2 -2
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +5 -9
- package/dist/report/react/fixtures.js +110 -147
- package/dist/report/react/index.d.ts +15 -5
- package/dist/report/react/index.js +18 -7
- package/dist/report/report.d.ts +137 -16
- package/dist/report/report.js +259 -28
- package/dist/report/text/faces.d.ts +17 -19
- package/dist/report/text/faces.js +253 -184
- package/dist/report/text/plot.js +1 -1
- package/dist/report/text/table.js +38 -7
- package/dist/report/tree.d.ts +90 -40
- package/dist/report/tree.js +252 -94
- package/dist/report/types.d.ts +247 -284
- package/dist/report/types.js +4 -3
- package/dist/report/web.d.ts +21 -5
- package/dist/report/web.js +42 -16
- package/dist/results/select.d.ts +38 -16
- package/dist/results/select.js +73 -25
- package/dist/results/types.d.ts +49 -14
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +4 -2
- package/dist/shared/aggregate.js +8 -7
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/README.md +44 -0
- package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
- package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
- package/docs-site/zh/examples/index.mdx +50 -0
- package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
- package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
- package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
- package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
- package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
- package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
- package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
- package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
- package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
- package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
- package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
- package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
- package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
- package/docs-site/zh/how-to/publish-report.mdx +105 -0
- package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
- package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
- package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
- package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
- package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
- package/docs-site/zh/index.mdx +24 -26
- package/docs-site/zh/introduction.mdx +8 -8
- package/docs-site/zh/reference/builtin-agents.mdx +32 -5
- package/docs-site/zh/reference/capabilities.mdx +8 -8
- package/docs-site/zh/reference/cli.mdx +40 -12
- package/docs-site/zh/reference/define-agent.mdx +58 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +3 -3
- package/docs-site/zh/reference/expect.mdx +26 -1
- package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
- package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
- package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
- package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
- package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
- package/package.json +10 -2
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +13 -2
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/streaming.ts +2 -2
- package/src/agents/types.ts +71 -8
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +446 -124
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +162 -30
- package/src/context/session.test.ts +2 -1
- package/src/context/session.ts +115 -7
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +81 -17
- package/src/i18n/zh-CN.ts +80 -17
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +178 -61
- package/src/report/built-in/index.tsx +9 -0
- package/src/report/components.tsx +625 -279
- package/src/report/compute.ts +723 -491
- package/src/report/dual-render.test.tsx +741 -1024
- package/src/report/flag.ts +104 -12
- package/src/report/format.ts +32 -12
- package/src/report/index.ts +119 -46
- package/src/report/load.ts +3 -2
- package/src/report/locale.ts +136 -65
- package/src/report/metrics.ts +108 -25
- package/src/report/primitives.tsx +196 -45
- package/src/report/react/AttemptList.tsx +30 -43
- package/src/report/react/DeltaTable.tsx +63 -45
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +73 -0
- package/src/report/react/ExperimentList.tsx +50 -32
- package/src/report/react/MetricBars.tsx +5 -4
- package/src/report/react/MetricLine.tsx +13 -8
- package/src/report/react/MetricMatrix.tsx +2 -2
- package/src/report/react/MetricScatter.tsx +86 -34
- package/src/report/react/MetricTable.tsx +4 -76
- package/src/report/react/ScopeSummary.tsx +86 -0
- package/src/report/react/Scoreboard.tsx +28 -10
- package/src/report/react/cell.tsx +2 -2
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +89 -5
- package/src/report/react/fixtures.ts +114 -154
- package/src/report/react/index.tsx +24 -39
- package/src/report/react/render.test.tsx +138 -158
- package/src/report/react/styles.css +243 -82
- package/src/report/report.test.ts +779 -841
- package/src/report/report.ts +423 -41
- package/src/report/text/faces.ts +290 -193
- package/src/report/text/plot.ts +1 -1
- package/src/report/text/table.ts +44 -7
- package/src/report/tree.ts +362 -104
- package/src/report/types.ts +261 -271
- package/src/report/web.ts +63 -20
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +13 -11
- package/src/results/attempt-evidence.ts +20 -13
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +150 -60
- package/src/results/host-equivalence.test.ts +34 -20
- package/src/results/index.ts +12 -4
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +15 -5
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +89 -54
- package/src/results/select.ts +104 -34
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +43 -14
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +243 -37
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +8 -6
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +50 -67
- package/src/show/index.ts +127 -56
- package/src/show/render.ts +662 -131
- package/src/show/report-host.test.ts +188 -0
- package/src/show/report-host.ts +375 -0
- package/src/show/show.test.ts +320 -54
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/App.test.tsx +69 -0
- package/src/view/app/App.tsx +144 -48
- package/src/view/app/components/AttemptModal.tsx +423 -11
- package/src/view/app/components/CodeView.tsx +41 -14
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +37 -17
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/app/main.tsx +13 -8
- package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
- package/src/view/app/types.ts +4 -1
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +10 -3
- package/src/view/data.ts +155 -49
- package/src/view/index.ts +56 -41
- package/src/view/server.ts +37 -15
- package/src/view/shared/types.ts +34 -5
- package/src/view/styles.css +227 -0
- package/src/view/view-report.test.ts +167 -62
- package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
- package/dist/report/built-ins/experiment-comparison.js +0 -13
- package/dist/report/built-ins/index.d.ts +0 -1
- package/dist/report/built-ins/index.js +0 -2
- package/dist/report/react/GroupSummary.d.ts +0 -8
- package/dist/report/react/GroupSummary.js +0 -8
- package/dist/report/react/RunOverview.d.ts +0 -8
- package/dist/report/react/RunOverview.js +0 -12
- package/docs-site/zh/example/ai-agent-application.mdx +0 -152
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
- package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
- package/docs-site/zh/example/showcase.mdx +0 -39
- package/docs-site/zh/guides/publish-report.mdx +0 -91
- package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
- package/src/report/built-in-user-parity.test.tsx +0 -640
- package/src/report/built-ins/experiment-comparison.tsx +0 -19
- package/src/report/built-ins/index.ts +0 -2
- package/src/report/react/GroupSummary.tsx +0 -66
- package/src/report/react/RunOverview.tsx +0 -109
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
- /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
- /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
|
@@ -1,11 +1,9 @@
|
|
|
1
|
+
// cases: docs/engineering/unit-tests/reports/cases.md
|
|
1
2
|
// 「不 hydrate 也完整」的验收测试:每个组件过 renderToStaticMarkup,
|
|
2
3
|
// 断言纯静态 HTML 里就有全部关键内容——数字、覆盖率角标、缺数据文案、
|
|
3
4
|
// 散点的 SVG 与系列名、truncated 行、attemptHref 链接。
|
|
4
|
-
//
|
|
5
|
+
// 另外锁一条契约:维度键跨组件同色。
|
|
5
6
|
|
|
6
|
-
import { readFileSync, readdirSync } from "node:fs";
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
7
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
10
8
|
import { describe, expect, it } from "vitest";
|
|
11
9
|
import type { AttemptLocator } from "../../results/locator.ts";
|
|
@@ -18,8 +16,8 @@ import {
|
|
|
18
16
|
MetricMatrix,
|
|
19
17
|
MetricScatter,
|
|
20
18
|
MetricTable,
|
|
21
|
-
RunOverview,
|
|
22
19
|
Scoreboard,
|
|
20
|
+
ScopeSummary,
|
|
23
21
|
} from "./index.tsx";
|
|
24
22
|
import { colorClassForKey, seriesClassForKey } from "./colors.ts";
|
|
25
23
|
import {
|
|
@@ -28,62 +26,53 @@ import {
|
|
|
28
26
|
evalListItems,
|
|
29
27
|
experimentListItems,
|
|
30
28
|
matrixData,
|
|
31
|
-
overviewData,
|
|
32
|
-
overviewWithCost,
|
|
33
29
|
scatterData,
|
|
30
|
+
scopeSummaryData,
|
|
34
31
|
scoreboardData,
|
|
35
32
|
tableData,
|
|
36
|
-
tableDataWithMeta,
|
|
37
33
|
} from "./fixtures.ts";
|
|
38
34
|
|
|
39
35
|
const attemptHref = (locator: AttemptLocator) => `/attempts/${locator}`;
|
|
40
36
|
|
|
41
|
-
describe("
|
|
42
|
-
const html = renderToStaticMarkup(<
|
|
37
|
+
describe("ScopeSummary", () => {
|
|
38
|
+
const html = renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} />);
|
|
43
39
|
|
|
44
|
-
it("KPI
|
|
45
|
-
expect(html).toContain("nre-
|
|
46
|
-
expect(html).toContain("<dd>
|
|
47
|
-
expect(html).toContain("<dd>
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
expect(html).
|
|
52
|
-
expect(html).toContain("
|
|
53
|
-
expect(html).toContain("
|
|
40
|
+
it("KPI:experiment/eval/attempt 数、成功率与总成本原样渲染(不从计票重算)", () => {
|
|
41
|
+
expect(html).toContain("nre-scope-summary");
|
|
42
|
+
expect(html).toContain("<dd>2</dd>"); // experiments
|
|
43
|
+
expect(html).toContain("<dd>6</dd>"); // evals
|
|
44
|
+
expect(html).toContain("<dd>9</dd>"); // attempts
|
|
45
|
+
// endToEndPassRate.display 原样渲染(两级聚合 60%),不是 eval 计票 3/5 = 60% 巧合之外的重算;
|
|
46
|
+
// attempt 计票 4/9 ≈ 44% 也不该出现
|
|
47
|
+
expect(html).toContain("60%");
|
|
48
|
+
expect(html).not.toContain("44%");
|
|
49
|
+
expect(html).toContain("$1.50");
|
|
54
50
|
});
|
|
55
51
|
|
|
56
|
-
it("
|
|
57
|
-
expect(html).toContain("
|
|
58
|
-
expect(html).
|
|
59
|
-
const
|
|
60
|
-
expect(
|
|
52
|
+
it("votes 默认 eval 级计票;votes='attempt' 切换显示但 data 不变", () => {
|
|
53
|
+
expect(html).toContain("3 passed");
|
|
54
|
+
expect(html).toContain('data-votes="eval"');
|
|
55
|
+
const attempts = renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} votes="attempt" />);
|
|
56
|
+
expect(attempts).toContain("4 passed");
|
|
57
|
+
expect(attempts).toContain('data-votes="attempt"');
|
|
61
58
|
});
|
|
62
59
|
|
|
63
|
-
it("
|
|
64
|
-
expect(html).toContain("2 snapshots");
|
|
65
|
-
expect(html).toContain("compare/bub");
|
|
60
|
+
it("时间窗来自 range,不编造当前时间", () => {
|
|
66
61
|
expect(html).toContain("2026-07-01T10:00:00Z");
|
|
67
|
-
expect(html).toContain("
|
|
68
|
-
expect(html).toContain("nre-warnings");
|
|
62
|
+
expect(html).toContain("2026-07-01T11:30:00Z");
|
|
69
63
|
});
|
|
70
64
|
});
|
|
71
65
|
|
|
72
66
|
describe("MetricTable", () => {
|
|
73
67
|
const html = renderToStaticMarkup(<MetricTable data={tableData} attemptHref={attemptHref} />);
|
|
74
68
|
|
|
75
|
-
it("
|
|
76
|
-
// fixture 里 codex(50%)在 bub(87%)前面,输出必须保持
|
|
77
|
-
expect(html.indexOf(">codex<")).toBeGreaterThan(-1);
|
|
78
|
-
expect(html.indexOf(">codex<")).toBeLessThan(html.indexOf(">bub<"));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("列头带 label、unit 与 better 方向", () => {
|
|
69
|
+
it("列头带 label、unit 与 better 方向,首列是 rowDimension", () => {
|
|
82
70
|
expect(html).toContain("pass rate");
|
|
83
71
|
expect(html).toContain("(%)");
|
|
84
72
|
expect(html).toContain("code lines");
|
|
85
73
|
expect(html).toContain("↑");
|
|
86
74
|
expect(html).toContain("↓");
|
|
75
|
+
expect(html).toContain(">agent</th>");
|
|
87
76
|
});
|
|
88
77
|
|
|
89
78
|
it("数字与覆盖率角标:samples < total 如实标出", () => {
|
|
@@ -98,7 +87,7 @@ describe("MetricTable", () => {
|
|
|
98
87
|
});
|
|
99
88
|
|
|
100
89
|
it("refs + attemptHref 出普通 <a>", () => {
|
|
101
|
-
expect(html).toContain('href="/attempts/@
|
|
90
|
+
expect(html).toContain('href="/attempts/@1a0a0a0a"');
|
|
102
91
|
});
|
|
103
92
|
|
|
104
93
|
it("渐进增强的 data 属性:所有表头 data-nre-sort、格子 data-sort-value(无 JS 时纯属性,内容完整)", () => {
|
|
@@ -108,30 +97,9 @@ describe("MetricTable", () => {
|
|
|
108
97
|
// 缺数据格子的排序值为空串:enhance.js 排序时恒沉底
|
|
109
98
|
expect(html).toContain('data-sort-value=""');
|
|
110
99
|
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
114
|
-
const html = renderToStaticMarkup(<MetricTable data={tableDataWithMeta} />);
|
|
115
|
-
|
|
116
|
-
it("meta 在场补 Model / Agent 列,列序 experiment、model、agent、指标、verdicts", () => {
|
|
117
|
-
expect(html).toContain(">Model</th>");
|
|
118
|
-
expect(html).toContain(">Agent</th>");
|
|
119
|
-
expect(html).toContain(">Verdicts</th>");
|
|
120
|
-
expect(html.indexOf(">Model</th>")).toBeLessThan(html.indexOf(">Agent</th>"));
|
|
121
|
-
expect(html.indexOf(">Agent</th>")).toBeLessThan(html.indexOf("pass rate"));
|
|
122
|
-
expect(html).toContain("gpt-5.4");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it("verdict 计票列:eval 级折叠口径的 pill,零计数不出 pill", () => {
|
|
126
|
-
expect(html).toContain("nre-verdict-pill");
|
|
127
|
-
expect(html).toContain("1 passed");
|
|
128
|
-
expect(html).toContain("1 failed");
|
|
129
|
-
expect(html).toContain("2 passed");
|
|
130
|
-
expect(html).not.toContain("0 errored");
|
|
131
|
-
});
|
|
132
100
|
|
|
133
101
|
it("filter 开:表格前渲染 data-nre-filter 输入框(无 JS 静默无功能),仍无 <script>", () => {
|
|
134
|
-
const filtered = renderToStaticMarkup(<MetricTable data={
|
|
102
|
+
const filtered = renderToStaticMarkup(<MetricTable data={tableData} filter />);
|
|
135
103
|
expect(filtered).toContain("data-nre-filter");
|
|
136
104
|
expect(filtered).toContain('class="nre-filter"');
|
|
137
105
|
expect(filtered.indexOf("nre-filter")).toBeLessThan(filtered.indexOf("<table"));
|
|
@@ -139,11 +107,8 @@ describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
|
139
107
|
expect(filtered).not.toContain("<script");
|
|
140
108
|
});
|
|
141
109
|
|
|
142
|
-
it("locale=zh-CN:chrome
|
|
143
|
-
const zh = renderToStaticMarkup(<MetricTable data={
|
|
144
|
-
expect(zh).toContain(">模型</th>");
|
|
145
|
-
expect(zh).toContain(">结果</th>");
|
|
146
|
-
expect(zh).toContain("1 通过");
|
|
110
|
+
it("locale=zh-CN:chrome 文案走字典;display 不本地化", () => {
|
|
111
|
+
const zh = renderToStaticMarkup(<MetricTable data={tableData} filter locale="zh-CN" />);
|
|
147
112
|
expect(zh).toContain('placeholder="筛选行…"');
|
|
148
113
|
expect(zh).toContain("50%"); // display 是 format 产物,不本地化
|
|
149
114
|
});
|
|
@@ -152,25 +117,17 @@ describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
|
152
117
|
describe("MetricMatrix", () => {
|
|
153
118
|
const html = renderToStaticMarkup(<MetricMatrix data={matrixData} attemptHref={attemptHref} />);
|
|
154
119
|
|
|
155
|
-
it("caption 标出指标与行列维度", () => {
|
|
120
|
+
it("caption 标出指标与行列维度(rowDimension × columnDimension)", () => {
|
|
156
121
|
expect(html).toContain("pass rate");
|
|
157
122
|
expect(html).toContain("eval × agent");
|
|
158
123
|
});
|
|
159
124
|
|
|
160
|
-
it("
|
|
161
|
-
expect(html.match(/nre-td-empty/g)).toHaveLength(1);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it("格子数字与 refs 下钻链接", () => {
|
|
125
|
+
it("格子数字与 refs 下钻链接;稀疏格子空着不补 0", () => {
|
|
165
126
|
expect(html).toContain("100%");
|
|
166
127
|
expect(html).toContain("0%");
|
|
167
|
-
expect(html).toContain('href="/attempts/@
|
|
168
|
-
expect(html).toContain('href="/attempts/@
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
it("列头(维度键)带稳定散列配色 class", () => {
|
|
172
|
-
expect(html).toContain(colorClassForKey("bub"));
|
|
173
|
-
expect(html).toContain(colorClassForKey("codex"));
|
|
128
|
+
expect(html).toContain('href="/attempts/@1b3b3b3b"');
|
|
129
|
+
expect(html).toContain('href="/attempts/@1b7b7b7b"');
|
|
130
|
+
expect(html).toContain("nre-td-empty");
|
|
174
131
|
});
|
|
175
132
|
});
|
|
176
133
|
|
|
@@ -183,19 +140,20 @@ describe("Scoreboard", () => {
|
|
|
183
140
|
expect(html).toContain("/ 100");
|
|
184
141
|
});
|
|
185
142
|
|
|
186
|
-
it("分科小计 earned/possible", () => {
|
|
187
|
-
expect(html).toContain("14/16");
|
|
188
|
-
expect(html).toContain("3/4");
|
|
143
|
+
it("分科小计 display(earned/possible 与同尺度百分比)", () => {
|
|
144
|
+
expect(html).toContain("14/16 (87.5%)");
|
|
145
|
+
expect(html).toContain("3/4 (75%)");
|
|
189
146
|
});
|
|
190
147
|
|
|
191
|
-
it("
|
|
192
|
-
expect(html).toContain("1 eval
|
|
193
|
-
expect(html).toContain("2 evals
|
|
148
|
+
it("notRun 与 unscorable 分开注脚,不合并成一个笼统的缺失数", () => {
|
|
149
|
+
expect(html).toContain("1 eval not run, scored 0");
|
|
150
|
+
expect(html).toContain("2 evals unscorable, scored 0");
|
|
194
151
|
});
|
|
195
152
|
|
|
196
|
-
it("
|
|
153
|
+
it("实际生效的权重表可审计;题集外被忽略的 eval 如实报数", () => {
|
|
197
154
|
expect(html).toContain("algebra/ ×2");
|
|
198
155
|
expect(html).toContain("others ×1");
|
|
156
|
+
expect(html).toContain("1 eval outside the question set ignored");
|
|
199
157
|
});
|
|
200
158
|
});
|
|
201
159
|
|
|
@@ -220,10 +178,37 @@ describe("MetricScatter", () => {
|
|
|
220
178
|
expect(html).toContain("pass rate(%)");
|
|
221
179
|
});
|
|
222
180
|
|
|
223
|
-
it("better
|
|
181
|
+
it("轴方向跟随 better:成本轴(lower)反向,便宜($5)在贵($10)右边;提示恒为「越靠右上越好」", () => {
|
|
224
182
|
expect(cxOf("compare/bub-low")).toBeGreaterThan(cxOf("compare/bub-high"));
|
|
225
|
-
// y 轴
|
|
183
|
+
// y 轴(higher)正向:通过率高(90%)在低(50%)上方(SVG y 向下增长)
|
|
226
184
|
expect(cyOf("compare/bub-high")).toBeLessThan(cyOf("compare/bub-low"));
|
|
185
|
+
expect(html).toContain("better → upper right");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("反向轴的刻度显示真实值:x 刻度从左到右数值递减(值大在左),数字不变", () => {
|
|
189
|
+
// x 轴刻度 <text class="nre-scatter-tick" x="…">$N</text>:抓出 (x, 值) 对,按 x 升序后值应递减。
|
|
190
|
+
const ticks = [...html.matchAll(/nre-scatter-tick" x="([\d.]+)" y="[\d.]+" text-anchor="middle">\$([\d.]+)/g)].map(
|
|
191
|
+
(m) => ({ px: Number(m[1]), value: Number(m[2]) }),
|
|
192
|
+
);
|
|
193
|
+
expect(ticks.length).toBeGreaterThanOrEqual(2);
|
|
194
|
+
const byPx = [...ticks].sort((a, b) => a.px - b.px);
|
|
195
|
+
for (let i = 1; i < byPx.length; i++) {
|
|
196
|
+
expect(byPx[i]!.value).toBeLessThan(byPx[i - 1]!.value);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("任一轴未声明 better:该轴正向渲染且整图无方向提示(组件不猜「更好」朝哪边)", () => {
|
|
201
|
+
const noBetter = renderToStaticMarkup(
|
|
202
|
+
<MetricScatter data={{ ...scatterData, x: { key: "cost", label: "cost", unit: "$" } }} />,
|
|
203
|
+
);
|
|
204
|
+
expect(noBetter).not.toContain("better →");
|
|
205
|
+
// x 正向:便宜($5)回到贵($10)左边。
|
|
206
|
+
const cx = (key: string): number => {
|
|
207
|
+
const m = noBetter.match(new RegExp(`data-key="${key}"[\\s\\S]*?\\bcx="([\\d.]+)"`));
|
|
208
|
+
expect(m, `circle for ${key}`).toBeTruthy();
|
|
209
|
+
return Number(m![1]);
|
|
210
|
+
};
|
|
211
|
+
expect(cx("compare/bub-low")).toBeLessThan(cx("compare/bub-high"));
|
|
227
212
|
});
|
|
228
213
|
|
|
229
214
|
it("同系列点连线,系列色走类名(nre-series-cN,CSS 上色跟随深浅主题),图例列系列名", () => {
|
|
@@ -231,21 +216,31 @@ describe("MetricScatter", () => {
|
|
|
231
216
|
expect(html).toContain(`nre-scatter-line ${seriesClassForKey("bub")}`);
|
|
232
217
|
// 渲染面零内联 hex:深色主题下由 CSS 变量切换
|
|
233
218
|
expect(html).not.toMatch(/#[0-9a-f]{6}/i);
|
|
234
|
-
// 图例:codex 只有 1 个可画点、不出线,但系列名仍在图例里
|
|
235
219
|
expect(html).toContain(">bub</span>");
|
|
236
220
|
expect(html).toContain(">codex</span>");
|
|
237
221
|
});
|
|
238
222
|
|
|
239
|
-
it("niceTicks 网格与每点直接标签(
|
|
223
|
+
it("niceTicks 网格与每点直接标签(末段唯一时缩成末段)", () => {
|
|
240
224
|
expect(html).toContain("nre-scatter-grid");
|
|
241
225
|
expect(html.match(/nre-scatter-tick/g)!.length).toBeGreaterThanOrEqual(6);
|
|
242
226
|
expect(html).toContain(">bub-low</text>");
|
|
243
227
|
expect(html).toContain(">codex-mid</text>");
|
|
244
228
|
});
|
|
245
229
|
|
|
246
|
-
it("
|
|
247
|
-
|
|
248
|
-
|
|
230
|
+
it("末段重名的点使用能区分它们的最短路径后缀", () => {
|
|
231
|
+
const dupes = renderToStaticMarkup(
|
|
232
|
+
<MetricScatter
|
|
233
|
+
data={{
|
|
234
|
+
...scatterData,
|
|
235
|
+
rows: [
|
|
236
|
+
{ ...scatterData.rows[0]!, key: "compare/a/run" },
|
|
237
|
+
{ ...scatterData.rows[1]!, key: "compare/b/run" },
|
|
238
|
+
],
|
|
239
|
+
}}
|
|
240
|
+
/>,
|
|
241
|
+
);
|
|
242
|
+
expect(dupes).toContain(">a/run</text>");
|
|
243
|
+
expect(dupes).toContain(">b/run</text>");
|
|
249
244
|
});
|
|
250
245
|
|
|
251
246
|
it("hover 退化为 <title>:display 与 samples/total", () => {
|
|
@@ -298,71 +293,57 @@ describe("DeltaTable", () => {
|
|
|
298
293
|
expect(html).toContain(">Δ</span>");
|
|
299
294
|
});
|
|
300
295
|
|
|
301
|
-
it("
|
|
296
|
+
it("涨跌好坏按数据侧算好的 outcome 配色:improved / regressed / unchanged / unavailable", () => {
|
|
302
297
|
expect(html).toContain("nre-delta-good");
|
|
303
298
|
expect(html).toContain("nre-delta-bad");
|
|
304
299
|
expect(html).toContain("nre-delta-flat");
|
|
300
|
+
expect(html).toContain('data-outcome="unavailable"');
|
|
305
301
|
});
|
|
306
302
|
|
|
307
|
-
it("
|
|
308
|
-
expect(html).toContain("
|
|
309
|
-
expect(html).toContain("
|
|
303
|
+
it("每行显示作者声明的 pair label 与 A → B 的维度键", () => {
|
|
304
|
+
expect(html).toContain(">bub</span>");
|
|
305
|
+
expect(html).toContain("compare/bub → compare/bub--agents-md");
|
|
310
306
|
});
|
|
311
307
|
|
|
312
|
-
it("
|
|
313
|
-
|
|
308
|
+
it("0 对显示明确空态并报告配对域实验数", () => {
|
|
309
|
+
const empty = renderToStaticMarkup(<DeltaTable data={{ ...deltaData, experiments: 3, rows: [] }} />);
|
|
310
|
+
expect(empty).not.toContain("<table");
|
|
311
|
+
expect(empty).toContain("3 experiments, 0 comparable pairs");
|
|
314
312
|
});
|
|
315
313
|
});
|
|
316
314
|
|
|
317
|
-
// AttemptList / EvalList / ExperimentList 的公开(报告组件)Props 没有 attemptHref 覆盖口子——
|
|
318
|
-
// 证据室深链恒经 ctx.attemptHref,宿主外直接嵌进 React 应用时退化为默认 `#/attempt/<locator>`
|
|
319
|
-
// (tree.ts 的 DEFAULT_WEB_CONTEXT),不是纯展示、也不发明另一套断链(与 MetricTable 等
|
|
320
|
-
// 可选 attemptHref 的组件不同,这三个组件的下钻不是可选行为)。
|
|
321
|
-
|
|
322
315
|
describe("AttemptList", () => {
|
|
323
|
-
const html = renderToStaticMarkup(<AttemptList
|
|
324
|
-
|
|
325
|
-
it("逐条断言:name、score、detail、evidence", () => {
|
|
326
|
-
expect(html).toContain("roots-correct");
|
|
327
|
-
expect(html).toContain("expected x=2, got x=3");
|
|
328
|
-
expect(html).toContain("judge: sign flipped when substituting into the quadratic formula");
|
|
329
|
-
});
|
|
316
|
+
const html = renderToStaticMarkup(<AttemptList data={attemptListItems} />);
|
|
330
317
|
|
|
331
|
-
it("
|
|
332
|
-
expect(html).toContain("
|
|
318
|
+
it("显示算好的 failureSummary 与 +N more failures 计数,不重算摘要", () => {
|
|
319
|
+
expect(html).toContain("gate: roots-correct · expected x=2 · received x=3");
|
|
320
|
+
expect(html).toContain("+1 more failure");
|
|
321
|
+
// errored 的一层摘要(phase · code · message)
|
|
322
|
+
expect(html).toContain("eval.run · unexpected-error · TypeError");
|
|
333
323
|
});
|
|
334
324
|
|
|
335
|
-
it("total >
|
|
336
|
-
const html2 = renderToStaticMarkup(<AttemptList
|
|
325
|
+
it("total > data.length 时如实报「还有 n 条没列」", () => {
|
|
326
|
+
const html2 = renderToStaticMarkup(<AttemptList data={attemptListItems} total={attemptListItems.length + 2} />);
|
|
337
327
|
expect(html2).toContain("and 2 more not shown");
|
|
338
|
-
// 不传 total(或 total ===
|
|
328
|
+
// 不传 total(或 total === data.length)不产出截断文案
|
|
339
329
|
expect(html).not.toContain("more not shown");
|
|
340
330
|
});
|
|
341
331
|
|
|
342
|
-
it("
|
|
343
|
-
expect(html).toContain(
|
|
344
|
-
expect(html
|
|
345
|
-
expect(html).not.toMatch(/\[[EXD⏱,]+\]/);
|
|
332
|
+
it("costUSD 为 null 时不显示成本,也不伪造 $0", () => {
|
|
333
|
+
expect(html).toContain("$0.12");
|
|
334
|
+
expect(html.match(/nre-attempt-cost/g)).toHaveLength(1); // errored 那条 costUSD: null
|
|
346
335
|
});
|
|
347
336
|
|
|
348
|
-
it("
|
|
349
|
-
expect(html).toContain("<details");
|
|
350
|
-
expect(html).toContain("<summary>");
|
|
337
|
+
it("AttemptList 自身不展开断言详情", () => {
|
|
338
|
+
expect(html).not.toContain("<details");
|
|
351
339
|
});
|
|
352
340
|
});
|
|
353
341
|
|
|
354
342
|
describe("EvalList", () => {
|
|
355
|
-
const html = renderToStaticMarkup(<EvalList
|
|
356
|
-
|
|
357
|
-
it("每项一个 experimentId + evalId,判定与分数在场", () => {
|
|
358
|
-
expect(html).toContain("algebra/quadratic");
|
|
359
|
-
expect(html).toContain("geometry/angles");
|
|
360
|
-
expect(html).toContain("compare/bub");
|
|
361
|
-
expect(html).toContain("compare/codex");
|
|
362
|
-
});
|
|
343
|
+
const html = renderToStaticMarkup(<EvalList data={evalListItems} />);
|
|
363
344
|
|
|
364
345
|
it("展开到这道题的 Attempt(与 AttemptList 同一套 AttemptRow 渲染)", () => {
|
|
365
|
-
expect(html).toContain('href="#/attempt/@
|
|
346
|
+
expect(html).toContain('href="#/attempt/@1a4a4a4a"');
|
|
366
347
|
expect(html).toContain("roots-correct");
|
|
367
348
|
});
|
|
368
349
|
|
|
@@ -373,34 +354,45 @@ describe("EvalList", () => {
|
|
|
373
354
|
});
|
|
374
355
|
|
|
375
356
|
describe("ExperimentList", () => {
|
|
376
|
-
const html = renderToStaticMarkup(<ExperimentList
|
|
357
|
+
const html = renderToStaticMarkup(<ExperimentList data={experimentListItems} filter />);
|
|
377
358
|
|
|
378
|
-
it("web 面是带过滤框与八个固定列头的 experiment 比较表", () => {
|
|
359
|
+
it("web 面是带过滤框与八个固定列头的 experiment 比较表(成本列头是 Cost)", () => {
|
|
379
360
|
expect(html).toContain('data-nre-experiment-filter=""');
|
|
380
|
-
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "
|
|
361
|
+
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "End-to-end pass rate", "Tokens", "Cost", "Result"]) {
|
|
381
362
|
expect(html).toContain(`>${header}</button>`);
|
|
382
363
|
}
|
|
364
|
+
expect(html).not.toContain("Est. cost");
|
|
383
365
|
expect(html).toContain('data-nre-experiment-sort="4" class="nre-sort-desc"');
|
|
384
366
|
});
|
|
385
367
|
|
|
386
|
-
it("主行:身份、agent/model
|
|
368
|
+
it("主行:身份、agent/model、官方两级聚合指标与 eval 级判定构成", () => {
|
|
387
369
|
expect(html).toContain("compare/bub");
|
|
388
370
|
expect(html).toContain("compare/codex");
|
|
389
371
|
expect(html).toContain("gpt-5.4");
|
|
390
|
-
expect(html).toContain("50%"); //
|
|
372
|
+
expect(html).toContain("50%"); // endToEndPassRate.display
|
|
391
373
|
expect(html).toContain("1 passed / 1 failed");
|
|
392
374
|
expect(html).toContain("memory=true");
|
|
393
375
|
});
|
|
394
376
|
|
|
395
|
-
it("展开到 Eval
|
|
377
|
+
it("展开到 Eval:父行只有折叠判定与题级聚合,失败摘要只在 Attempt 子行", () => {
|
|
396
378
|
expect(html).toContain("algebra/quadratic");
|
|
397
|
-
expect(html).toContain('href="#/attempt/@
|
|
398
|
-
expect(html).toContain('href="#/attempt/@
|
|
379
|
+
expect(html).toContain('href="#/attempt/@1a4a4a4a"');
|
|
380
|
+
expect(html).toContain('href="#/attempt/@1b5b5b5b"');
|
|
399
381
|
expect(html.match(/algebra\/quadratic/g)).toHaveLength(1);
|
|
400
382
|
expect(html).toContain("nre-experiment-eval-header");
|
|
401
|
-
expect(html.match(/nre-experiment-attempt-row/g)).toHaveLength(
|
|
383
|
+
expect(html.match(/nre-experiment-attempt-row/g)).toHaveLength(4);
|
|
402
384
|
expect(html).toContain("├─");
|
|
403
385
|
expect(html).toContain("└─");
|
|
386
|
+
// 主失败摘要只出现在 attempt 子行:两次(同一 eval 的两轮 attempt 各自的摘要),不在父行重复
|
|
387
|
+
expect(html.match(/gate: roots-correct/g)).toHaveLength(2);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("relativeTo 去掉组前缀只显示末段;data-sort-value 仍是完整 id", () => {
|
|
391
|
+
const relative = renderToStaticMarkup(<ExperimentList data={experimentListItems} relativeTo="compare" />);
|
|
392
|
+
expect(relative).toContain(">bub</b>");
|
|
393
|
+
expect(relative).toContain('data-sort-value="compare/bub"');
|
|
394
|
+
// 不传 relativeTo 显示完整 id
|
|
395
|
+
expect(html).toContain(">compare/bub</b>");
|
|
404
396
|
});
|
|
405
397
|
|
|
406
398
|
it("零 JS 靠原生 <details>,无 <script>", () => {
|
|
@@ -415,9 +407,8 @@ describe("跨组件契约", () => {
|
|
|
415
407
|
const table = renderToStaticMarkup(<MetricTable data={tableData} />);
|
|
416
408
|
const matrix = renderToStaticMarkup(<MetricMatrix data={matrixData} />);
|
|
417
409
|
const board = renderToStaticMarkup(<Scoreboard data={scoreboardData} />);
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
for (const html of [table, matrix, board, delta, attempts]) {
|
|
410
|
+
const attempts = renderToStaticMarkup(<AttemptList data={attemptListItems} />);
|
|
411
|
+
for (const html of [table, matrix, board, attempts]) {
|
|
421
412
|
expect(html).toContain(cls);
|
|
422
413
|
}
|
|
423
414
|
const scatter = renderToStaticMarkup(<MetricScatter data={scatterData} />);
|
|
@@ -426,27 +417,16 @@ describe("跨组件契约", () => {
|
|
|
426
417
|
|
|
427
418
|
it("静态输出不含 <script>:交互只靠 <a>/<details>/CSS", () => {
|
|
428
419
|
const all = [
|
|
429
|
-
renderToStaticMarkup(<
|
|
420
|
+
renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} />),
|
|
430
421
|
renderToStaticMarkup(<MetricTable data={tableData} attemptHref={attemptHref} />),
|
|
431
422
|
renderToStaticMarkup(<MetricMatrix data={matrixData} attemptHref={attemptHref} />),
|
|
432
423
|
renderToStaticMarkup(<Scoreboard data={scoreboardData} />),
|
|
433
424
|
renderToStaticMarkup(<MetricScatter data={scatterData} />),
|
|
434
425
|
renderToStaticMarkup(<DeltaTable data={deltaData} />),
|
|
435
|
-
renderToStaticMarkup(<AttemptList
|
|
436
|
-
renderToStaticMarkup(<EvalList
|
|
437
|
-
renderToStaticMarkup(<ExperimentList
|
|
426
|
+
renderToStaticMarkup(<AttemptList data={attemptListItems} />),
|
|
427
|
+
renderToStaticMarkup(<EvalList data={evalListItems} />),
|
|
428
|
+
renderToStaticMarkup(<ExperimentList data={experimentListItems} />),
|
|
438
429
|
].join("");
|
|
439
430
|
expect(all).not.toContain("<script");
|
|
440
431
|
});
|
|
441
|
-
|
|
442
|
-
it("组件源码零 hooks(本实验的「不 hydrate 也完整」用最笨的方式保证)", () => {
|
|
443
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
|
444
|
-
const sources = readdirSync(dir)
|
|
445
|
-
.filter((f) => (f.endsWith(".tsx") || f.endsWith(".ts")) && !f.includes(".test."))
|
|
446
|
-
.map((f) => readFileSync(join(dir, f), "utf8"));
|
|
447
|
-
expect(sources.length).toBeGreaterThanOrEqual(12);
|
|
448
|
-
for (const src of sources) {
|
|
449
|
-
expect(src).not.toMatch(/\buse[A-Z][A-Za-z]*\s*\(/);
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
432
|
});
|