From c18c8fcfbef59f944310033e8551156e01f2b1e0 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 13:09:19 +0800 Subject: [PATCH 1/9] test: add local VTable visual regression suite --- .gitignore | 3 + packages/vtable/__tests__/visual/README.md | 41 + .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 10890 ++++++++++++++++ .../vtable/__tests__/visual/cases/COVERAGE.md | 37 + .../vtable/__tests__/visual/cases/README.md | 21 + .../cases/analysis/aggregation-float.mjs | 26 + .../cases/analysis/aggregation-pagination.mjs | 35 + .../visual/cases/analysis/filter-api.mjs | 27 + .../visual/cases/api/update-columns.mjs | 25 + .../visual/cases/cells/checkbox-states.mjs | 35 + .../visual/cases/cells/inline-image.mjs | 35 + .../cases/cells/mixed-sparkline-progress.mjs | 34 + .../visual/cases/cells/switch-button.mjs | 34 + .../visual/cases/cells/wrapped-text.mjs | 31 + .../visual/cases/components/hover-tooltip.mjs | 40 + .../visual/cases/components/legend-resize.mjs | 33 + .../visual/cases/components/title.mjs | 39 + .../visual/cases/custom/progress-layout.mjs | 42 + .../visual/cases/data/nested-field.mjs | 26 + .../cases/data/promise-custom-merge.mjs | 50 + .../visual/cases/data/promise-keep-data.mjs | 39 + .../visual/cases/data/promise-source.mjs | 33 + .../visual/cases/edit/complete-input.mjs | 35 + .../visual/cases/edit/start-with-value.mjs | 38 + .../visual/cases/empty/list-resize.mjs | 27 + .../visual/cases/empty/pivot-tip.mjs | 22 + .../visual/cases/frozen/drag-adjust-count.mjs | 41 + .../visual/cases/frozen/drag-disabled.mjs | 43 + .../visual/cases/frozen/one-column-left.mjs | 22 + .../visual/cases/frozen/one-column-right.mjs | 22 + .../cases/frozen/pivot-max-frozen-width.mjs | 31 + .../visual/cases/frozen/right-bottom.mjs | 23 + .../cases/frozen/scroll-frozen-columns.mjs | 42 + .../cases/frozen/short-content-connected.mjs | 30 + .../visual/cases/frozen/top-bottom-border.mjs | 27 + .../visual/cases/gantt/baseline-bottom.mjs | 47 + .../visual/cases/gantt/baseline-overlap.mjs | 35 + .../cases/gantt/baseline-padding-function.mjs | 42 + .../cases/gantt/baseline-padding-static.mjs | 39 + .../visual/cases/gantt/baseline-top.mjs | 47 + .../visual/cases/gantt/empty-mark-line.mjs | 28 + .../cases/gantt/locate-offscreen-task.mjs | 62 + .../visual/cases/gantt/move-task-bar.mjs | 47 + .../cases/gantt/project-range-set-records.mjs | 33 + .../cases/gantt/taskbar-relative-rect.mjs | 60 + .../visual/cases/gantt/tree-move-resize.mjs | 60 + .../visual/cases/group/add-delete-records.mjs | 45 + .../visual/cases/group/one-column.mjs | 25 + .../cases/header/grid-tree-filter-expand.mjs | 62 + .../cases/header/grid-tree-transpose.mjs | 33 + .../visual/cases/header/grid-tree.mjs | 32 + .../visual/cases/header/hidden-nested.mjs | 28 + .../visual/cases/header/hidden-parent.mjs | 25 + .../visual/cases/header/level-span.mjs | 31 + .../visual/cases/header/merge-cells.mjs | 32 + .../visual/cases/header/row-series-number.mjs | 24 + .../visual/cases/header/sort-icon-hidden.mjs | 26 + .../vtable/__tests__/visual/cases/index.mjs | 165 + .../cases/interaction/blank-area-deselect.mjs | 46 + .../interaction/disable-select-callback.mjs | 45 + .../interaction/disabled-column-range.mjs | 51 + .../cases/interaction/drag-column-header.mjs | 51 + .../interaction/drag-row-series-select.mjs | 44 + .../cases/interaction/resize-row-height.mjs | 44 + .../visual/cases/interaction/select-cross.mjs | 34 + .../cases/keyboard/copy-paste-event.mjs | 47 + .../visual/cases/keyboard/cut-paste-event.mjs | 59 + .../keyboard/disabled-arrow-navigation.mjs | 45 + .../visual/cases/keyboard/select-all-body.mjs | 49 + .../visual/cases/language/cyrillic-wrap.mjs | 25 + .../visual/cases/layout/adaptive-width.mjs | 24 + .../visual/cases/layout/auto-width-height.mjs | 32 + .../cases/layout/canvas-size-options.mjs | 63 + .../cases/layout/container-fit-both.mjs | 27 + .../cases/layout/container-fit-height.mjs | 26 + .../layout/custom-compute-row-height.mjs | 28 + .../visual/cases/layout/key-size-config.mjs | 28 + .../cases/layout/limit-max-auto-width.mjs | 44 + .../cases/layout/min-max-adaptive-width.mjs | 33 + .../visual/cases/menu/disabled-item.mjs | 33 + .../visual/cases/menu/dropdown-highlight.mjs | 32 + .../cases/pivot-chart/bar-line-right-axis.mjs | 45 + .../cases/pivot-chart/box-plot-horizontal.mjs | 40 + .../visual/cases/pivot-chart/box-plot.mjs | 48 + .../pivot-chart/circle-packing-hierarchy.mjs | 40 + .../pivot-chart/combination-forecast.mjs | 55 + .../pivot-chart/crosshair-linkage-hover.mjs | 61 + .../pivot-chart/heatmap-two-indicators.mjs | 45 + .../cases/pivot-chart/histogram-color.mjs | 40 + .../cases/pivot-chart/histogram-overlap.mjs | 38 + .../visual/cases/pivot-chart/mark-line.mjs | 46 + .../cases/pivot-chart/pie-multi-select.mjs | 61 + .../visual/cases/pivot-chart/scatter-axes.mjs | 40 + .../cases/pivot-chart/sunburst-hierarchy.mjs | 40 + .../visual/cases/pivot/aggregation-rules.mjs | 41 + .../visual/cases/pivot/analysis-two-level.mjs | 38 + .../calculated-field-hidden-dependencies.mjs | 39 + .../cases/pivot/column-header-title.mjs | 52 + .../cases/pivot/corner-empty-matrix.mjs | 69 + .../cases/pivot/corner-remaining-variants.mjs | 53 + .../cases/pivot/corner-sort-one-dimension.mjs | 45 + .../pivot/corner-sort-two-dimensions.mjs | 46 + .../cases/pivot/corner-without-rows.mjs | 34 + .../cases/pivot/custom-merge-subtotal.mjs | 38 + .../cases/pivot/custom-total-data-tree.mjs | 56 + .../cases/pivot/empty-string-dimension.mjs | 38 + .../cases/pivot/indicator-sort-rule.mjs | 30 + .../cases/pivot/indicator-sort-subtotal.mjs | 33 + .../cases/pivot/initial-column-sort-state.mjs | 45 + .../visual/cases/pivot/no-indicators.mjs | 28 + .../cases/pivot/resize-indicator-group.mjs | 46 + .../cases/pivot/resize-indicator-row.mjs | 44 + .../visual/cases/pivot/tree-zero-expand.mjs | 51 + .../visual/cases/pivot/update-filter.mjs | 32 + .../pivot/update-option-row-header-width.mjs | 40 + .../pivot/update-pivot-sort-state-click.mjs | 73 + .../cases/pivot/virtual-column-total.mjs | 48 + .../cases/plugins/context-menu-click.mjs | 37 + .../cases/plugins/fill-handle-hit-area.mjs | 31 + .../cases/plugins/filter-hide-reorder.mjs | 47 + .../visual/cases/plugins/highlight-header.mjs | 33 + .../plugins/master-detail-auto-height.mjs | 53 + .../visual/cases/records/add-merged.mjs | 29 + .../visual/cases/records/add-pagination.mjs | 31 + .../visual/cases/records/add-sorted.mjs | 30 + .../visual/cases/records/array-path-add.mjs | 26 + .../records/delete-all-bottom-frozen.mjs | 26 + .../visual/cases/records/delete-merged.mjs | 29 + .../visual/cases/records/delete-sorted.mjs | 30 + .../visual/cases/records/update-merged.mjs | 37 + .../visual/cases/scroll/bar-to-side.mjs | 33 + .../visual/cases/scroll/pivot-wide-rail.mjs | 33 + .../visual/cases/sheet/add-columns.mjs | 33 + .../__tests__/visual/cases/sheet/add-rows.mjs | 40 + .../visual/cases/sheet/copy-paste.mjs | 62 + .../visual/cases/sheet/cross-tab-formula.mjs | 33 + .../cases/sheet/formula-auto-fill-copy.mjs | 58 + .../visual/cases/sheet/formula-edit.mjs | 33 + .../visual/cases/sheet/update-option.mjs | 35 + .../visual/cases/sort/initial-desc.mjs | 35 + .../cases/sort/initial-multiple-state.mjs | 33 + .../cases/sort/multiple-header-click.mjs | 50 + .../visual/cases/sort/update-state.mjs | 24 + .../cases/style/border-clip-direction.mjs | 27 + .../visual/cases/style/dashed-border.mjs | 23 + .../visual/cases/style/underline.mjs | 34 + .../visual/cases/table/list-basic.mjs | 24 + .../visual/cases/table/list-select-cell.mjs | 30 + .../__tests__/visual/cases/theme/arco.mjs | 29 + .../visual/cases/theme/dark-icons.mjs | 27 + .../visual/cases/theme/update-theme.mjs | 27 + .../cases/transpose/only-body-auto-width.mjs | 48 + .../visual/cases/transpose/theme-header.mjs | 39 + .../cases/transpose/update-option-off.mjs | 26 + .../visual/cases/tree/checkbox-add-record.mjs | 40 + .../cases/tree/checkbox-delete-record.mjs | 43 + .../tree/checkbox-record-index-clear.mjs | 59 + .../visual/cases/tree/checkbox-set-state.mjs | 33 + .../visual/cases/tree/filter-clear-lazy.mjs | 51 + .../cases/tree/lazy-record-children.mjs | 51 + .../visual/cases/tree/list-merge-expand.mjs | 33 + .../cases/tree/pagination-double-click.mjs | 57 + .../visual/cases/tree/zero-height-toggle.mjs | 61 + packages/vtable/__tests__/visual/page.html | 53 + .../__tests__/visual/playwright.config.mjs | 37 + packages/vtable/__tests__/visual/report.mjs | 442 + packages/vtable/__tests__/visual/reporter.mjs | 90 + packages/vtable/__tests__/visual/settings.mjs | 12 + .../vtable/__tests__/visual/visual.spec.mjs | 135 + packages/vtable/package.json | 1 + packages/vtable/scripts/visual-test.mjs | 86 + packages/vtable/scripts/visual-test.test.mjs | 19 + packages/vtable/scripts/visual/build.mjs | 137 + packages/vtable/scripts/visual/runner.mjs | 350 + packages/vtable/scripts/visual/runtime.mjs | 173 + 175 files changed, 18773 insertions(+) create mode 100644 packages/vtable/__tests__/visual/README.md create mode 100644 packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json create mode 100644 packages/vtable/__tests__/visual/cases/COVERAGE.md create mode 100644 packages/vtable/__tests__/visual/cases/README.md create mode 100644 packages/vtable/__tests__/visual/cases/analysis/aggregation-float.mjs create mode 100644 packages/vtable/__tests__/visual/cases/analysis/aggregation-pagination.mjs create mode 100644 packages/vtable/__tests__/visual/cases/analysis/filter-api.mjs create mode 100644 packages/vtable/__tests__/visual/cases/api/update-columns.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/checkbox-states.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/inline-image.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/mixed-sparkline-progress.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/switch-button.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/wrapped-text.mjs create mode 100644 packages/vtable/__tests__/visual/cases/components/hover-tooltip.mjs create mode 100644 packages/vtable/__tests__/visual/cases/components/legend-resize.mjs create mode 100644 packages/vtable/__tests__/visual/cases/components/title.mjs create mode 100644 packages/vtable/__tests__/visual/cases/custom/progress-layout.mjs create mode 100644 packages/vtable/__tests__/visual/cases/data/nested-field.mjs create mode 100644 packages/vtable/__tests__/visual/cases/data/promise-custom-merge.mjs create mode 100644 packages/vtable/__tests__/visual/cases/data/promise-keep-data.mjs create mode 100644 packages/vtable/__tests__/visual/cases/data/promise-source.mjs create mode 100644 packages/vtable/__tests__/visual/cases/edit/complete-input.mjs create mode 100644 packages/vtable/__tests__/visual/cases/edit/start-with-value.mjs create mode 100644 packages/vtable/__tests__/visual/cases/empty/list-resize.mjs create mode 100644 packages/vtable/__tests__/visual/cases/empty/pivot-tip.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/drag-adjust-count.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/drag-disabled.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/one-column-left.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/one-column-right.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/pivot-max-frozen-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/right-bottom.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/scroll-frozen-columns.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/short-content-connected.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/top-bottom-border.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/baseline-bottom.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/baseline-overlap.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/baseline-padding-function.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/baseline-padding-static.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/baseline-top.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/empty-mark-line.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/locate-offscreen-task.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/move-task-bar.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/project-range-set-records.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/taskbar-relative-rect.mjs create mode 100644 packages/vtable/__tests__/visual/cases/gantt/tree-move-resize.mjs create mode 100644 packages/vtable/__tests__/visual/cases/group/add-delete-records.mjs create mode 100644 packages/vtable/__tests__/visual/cases/group/one-column.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/grid-tree-filter-expand.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/grid-tree-transpose.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/grid-tree.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/hidden-nested.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/hidden-parent.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/level-span.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/merge-cells.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/row-series-number.mjs create mode 100644 packages/vtable/__tests__/visual/cases/header/sort-icon-hidden.mjs create mode 100644 packages/vtable/__tests__/visual/cases/index.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/blank-area-deselect.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/disable-select-callback.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/disabled-column-range.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/drag-column-header.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/drag-row-series-select.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/resize-row-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-cross.mjs create mode 100644 packages/vtable/__tests__/visual/cases/keyboard/copy-paste-event.mjs create mode 100644 packages/vtable/__tests__/visual/cases/keyboard/cut-paste-event.mjs create mode 100644 packages/vtable/__tests__/visual/cases/keyboard/disabled-arrow-navigation.mjs create mode 100644 packages/vtable/__tests__/visual/cases/keyboard/select-all-body.mjs create mode 100644 packages/vtable/__tests__/visual/cases/language/cyrillic-wrap.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/adaptive-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/auto-width-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/canvas-size-options.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/container-fit-both.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/container-fit-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/custom-compute-row-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/key-size-config.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/limit-max-auto-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/min-max-adaptive-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/menu/disabled-item.mjs create mode 100644 packages/vtable/__tests__/visual/cases/menu/dropdown-highlight.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/bar-line-right-axis.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/box-plot-horizontal.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/box-plot.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/circle-packing-hierarchy.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/combination-forecast.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/crosshair-linkage-hover.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/heatmap-two-indicators.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/histogram-color.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/histogram-overlap.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/mark-line.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/scatter-axes.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/sunburst-hierarchy.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/aggregation-rules.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/analysis-two-level.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/calculated-field-hidden-dependencies.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/column-header-title.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/corner-empty-matrix.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/corner-remaining-variants.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/corner-sort-one-dimension.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/corner-sort-two-dimensions.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/corner-without-rows.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/custom-merge-subtotal.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/custom-total-data-tree.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/empty-string-dimension.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/indicator-sort-rule.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/indicator-sort-subtotal.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/initial-column-sort-state.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/no-indicators.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/resize-indicator-group.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/resize-indicator-row.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/tree-zero-expand.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/update-filter.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/update-option-row-header-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/update-pivot-sort-state-click.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/virtual-column-total.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/context-menu-click.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/fill-handle-hit-area.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/filter-hide-reorder.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/highlight-header.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/master-detail-auto-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/add-merged.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/add-pagination.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/add-sorted.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/array-path-add.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/delete-all-bottom-frozen.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/delete-merged.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/delete-sorted.mjs create mode 100644 packages/vtable/__tests__/visual/cases/records/update-merged.mjs create mode 100644 packages/vtable/__tests__/visual/cases/scroll/bar-to-side.mjs create mode 100644 packages/vtable/__tests__/visual/cases/scroll/pivot-wide-rail.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/add-columns.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/add-rows.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/copy-paste.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/cross-tab-formula.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/formula-auto-fill-copy.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/formula-edit.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/update-option.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sort/initial-desc.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sort/initial-multiple-state.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sort/multiple-header-click.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sort/update-state.mjs create mode 100644 packages/vtable/__tests__/visual/cases/style/border-clip-direction.mjs create mode 100644 packages/vtable/__tests__/visual/cases/style/dashed-border.mjs create mode 100644 packages/vtable/__tests__/visual/cases/style/underline.mjs create mode 100644 packages/vtable/__tests__/visual/cases/table/list-basic.mjs create mode 100644 packages/vtable/__tests__/visual/cases/table/list-select-cell.mjs create mode 100644 packages/vtable/__tests__/visual/cases/theme/arco.mjs create mode 100644 packages/vtable/__tests__/visual/cases/theme/dark-icons.mjs create mode 100644 packages/vtable/__tests__/visual/cases/theme/update-theme.mjs create mode 100644 packages/vtable/__tests__/visual/cases/transpose/only-body-auto-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/transpose/theme-header.mjs create mode 100644 packages/vtable/__tests__/visual/cases/transpose/update-option-off.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/checkbox-add-record.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/checkbox-delete-record.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/checkbox-record-index-clear.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/checkbox-set-state.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/filter-clear-lazy.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/lazy-record-children.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/list-merge-expand.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/pagination-double-click.mjs create mode 100644 packages/vtable/__tests__/visual/cases/tree/zero-height-toggle.mjs create mode 100644 packages/vtable/__tests__/visual/page.html create mode 100644 packages/vtable/__tests__/visual/playwright.config.mjs create mode 100644 packages/vtable/__tests__/visual/report.mjs create mode 100644 packages/vtable/__tests__/visual/reporter.mjs create mode 100644 packages/vtable/__tests__/visual/settings.mjs create mode 100644 packages/vtable/__tests__/visual/visual.spec.mjs create mode 100644 packages/vtable/scripts/visual-test.mjs create mode 100644 packages/vtable/scripts/visual-test.test.mjs create mode 100644 packages/vtable/scripts/visual/build.mjs create mode 100644 packages/vtable/scripts/visual/runner.mjs create mode 100644 packages/vtable/scripts/visual/runtime.mjs diff --git a/.gitignore b/.gitignore index dc413e3d53..1dd398fad7 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,6 @@ tsconfig.tsbuildinfo # codex .omx/ + +# Local visual regression runs +.vtable-visual/ diff --git a/packages/vtable/__tests__/visual/README.md b/packages/vtable/__tests__/visual/README.md new file mode 100644 index 0000000000..7bd5901701 --- /dev/null +++ b/packages/vtable/__tests__/visual/README.md @@ -0,0 +1,41 @@ +# VTable 本地视觉回归 + +本工具在本机将当前工作区与官方 `VisActor/VTable` 的 `develop` 构建逐例截图比较。用例由 BugServer Photo case 人工筛选、去业务化改写而来,另含少量独立的基础用例;运行不依赖 BugServer。两侧共用冻结的用例副本,只替换 VTable 构建产物。截图差异需要人工检查;自比较通过只说明运行稳定。 + +## 准备 + +在仓库根目录使用 Node.js 22,安装 Rush 依赖和锁文件对应的 Chromium: + +```sh +node common/scripts/install-run-rush.js install --ignore-hooks +PLAYWRIGHT_SKIP_BROWSER_GC=1 node packages/vtable/node_modules/@playwright/test/cli.js install chromium +``` + +Linux 还需安装 Chromium 的系统库。`--check` 会实际启动浏览器做预检,但不会安装依赖或构建。 + +## 运行 + +```sh +node packages/vtable/scripts/visual-test.mjs --check +node packages/vtable/scripts/visual-test.mjs --list +node packages/vtable/scripts/visual-test.mjs --case list-basic --self-compare +node packages/vtable/scripts/visual-test.mjs --dir pivot +node packages/vtable/scripts/visual-test.mjs +node packages/vtable/scripts/visual-test.mjs --baseline <完整的40位commit-sha> +``` + +`--case` 选择一个用例,`--dir` 递归选择一个相对目录,两者互斥;不传则运行全部。`--self-compare` 在两个隔离的浏览器上下文中执行相同的本地构建,用于检查用例确定性。默认基线每次从官方仓库获取 `develop` 并固定本轮 SHA;`--baseline` 从官方仓库获取指定 SHA。基线按自己的锁文件独立安装与构建,缓存最近一次成功的基线产物。当前工作区每轮构建包含未提交修改。 + +按用例需要构建核心 `vtable`,以及 `editors`、`gantt`、`plugins`、`sheet` 的本地 UMD 包;透视图还加载当前依赖锁定的 `vchart` 浏览器包。目录仅影响用例与所需包的选择;不会自动推断源码影响范围。 + +结果写入 Git 忽略的 `.vtable-visual/runs//`:`index.html` 可离线查看基线、当前和差异三图,`agent-summary.md` 便于快速定位失败,`summary.json` 保留结构化证据。退出码 `0` 表示所选用例均通过,`1` 表示视觉差异,`2` 表示执行、构建、资源或清理错误。报告可以整体复制,单独复制 HTML 会丢失相对图片。 + +正常结束、失败或 Ctrl+C 后,工具会回收本轮测试子进程、浏览器、HTTP 服务和临时基线 worktree。SIGKILL/断电后,先确认进程已结束,再检查 `git worktree list` 和 `.vtable-visual/running.lock`;不要删除其他任务的 worktree。 + +## 用例维护 + +目录说明及来源 ID 规则见 [用例指南](./cases/README.md)。开发完成后运行相关目录;提交 PR 前运行默认全量比较并检查差异。新功能或缺陷修复可以加独立用例。不得用放宽截图阈值、跳过语义断言或接受差异代替修复不稳定用例。工具自检: + +```sh +node --test packages/vtable/scripts/visual-test.test.mjs +``` diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json new file mode 100644 index 0000000000..36b3bbb5c7 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -0,0 +1,10890 @@ +{ + "product": "VTable", + "sourceSnapshotDigest": "de03690e63b7859f62ae14d4efc521951a1ce71d9d5db33881bcf98c37b54d1c", + "officialBaselineSha": "464c0630f7123fff5b398229fa81680a75a96430", + "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", + "counts": { + "baseline_failure": 1, + "deferred_interaction": 176, + "deferred_large_source": 70, + "deferred_resource": 31, + "deferred_static": 223, + "migrated": 20, + "privacy_excluded": 7 + }, + "entries": [ + { + "id": "64744dfe5d221c008666ee0f", + "sourceDigest": "0513512ecf16f0fe15276a214a1f4cec6057f7d98d1d47968981185cb9e26deb", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64744fa75d221c008666ee11", + "sourceDigest": "ed5a898b97b2b53fba66fd3ef435185e1fa77dc0adbfcd61640268eca19a3035", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "647450855d221c008666ee14", + "sourceDigest": "a6705fcf4831ede468bba0e1a14a84d1f9844eb60f4d7e76fdea791b3db2e41e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6474516f5d221c008666ee15", + "sourceDigest": "d183029f0da17e023895cc8b35813381d16a3f325809f5bf93be89b12c2e7825", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [ + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "647451ed5d221c008666ee16", + "sourceDigest": "b78b192dcabb36cf0b347398b0dc147e930da3591110cc3fcb506fddb6286c6e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6474534d5d221c008666ee18", + "sourceDigest": "ee1574cf4d8f6b80dc4bbac27994c8a8c1de68315575f819e8ab951986f2b354", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "pivot-column-header-title", + "verification": "columnHeaderLevelCount" + }, + { + "id": "6474549f5d221c008666ee1b", + "sourceDigest": "9f8d2b8d931313aecd3b5a9bb4e3603de5fd6ab80b01d0f6a0ce0385ff4a121e", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6474561b5d221c008666ee1c", + "sourceDigest": "842aa9374f1756a3e448b4fde58e7ebed3ec916de38a6dd7c40c7a6140adcbb7", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "647456e55d221c008666ee1d", + "sourceDigest": "fb69518e34b7fcf53d679c15ab36bf16c54657b058377dddfe92b43565f26540", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64745a015d221c008666ee1e", + "sourceDigest": "0a80c0e7aaaae466aadbf4d94850e833ec9cd52fcf37f5853ee79f684fb90b5c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64745a465d221c008666ee1f", + "sourceDigest": "7f29d689ad6ff1373b35a41b10266b3eb8cf86e5fc3bedecb72d55583ebf2a65", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64745a8d5d221c008666ee20", + "sourceDigest": "df900a36cea450fcf3707c09e7d520f6f6304e72dce468c8182d7e60024ca3e2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64745b055d221c008666ee21", + "sourceDigest": "9f52735cff829c20160fbf258f5454fecf2e10b458a6a68a67242f26de061212", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64745c2d5d221c008666ee24", + "sourceDigest": "2a5b5a786d6cda2e2a377e818668d2f1261f4cf0a8286e095a342f4cdee609c8", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 8, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "64745e5b5d221c008666ee26", + "sourceDigest": "91507f3cc89f93bad126555b003f924d1b5fdc5d8bc574ea804fad2955f853e8", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "autoFillWidth", + "autoFillHeight", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "64745ea95d221c008666ee27", + "sourceDigest": "56ae5acfd5d3e70912826b76551909991bfc2c5bc075bb77d31c7341612e5ecf", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64745f015d221c008666ee28", + "sourceDigest": "3cf949637e213f3b0b089503730e0bd68a70f507a41843efa329b706d4246ea1", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "647461145d221c008666ee2a", + "sourceDigest": "72d35721910eeade85b76e179ede5ece435852552104bb065567a037d1bd1fa6", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "647461665d221c008666ee2b", + "sourceDigest": "6d2837b80cc47bff05ad17bdf6259dac66accb413e1867abe3e0b6b96f8f79a1", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6479bcfbc48954008d952e0e", + "sourceDigest": "f459933015d76abe8b3062b41fcb2e05543b3c58c34f4fa5f330b890df1e46d7", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6479bdf9c48954008d952e1a", + "sourceDigest": "8bbfa19061dbfad27ebe1a99edb4c0647f8e94970a3d0563662bf1b332353fac", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 6, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6479c059c48954008d952e2f", + "sourceDigest": "05ce851ee2de6291c4b40abdf880be0af80d50970bf1d409b00727ddcb172b58", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6479c0d0c48954008d952e31", + "sourceDigest": "684b7ca5ec0339c45710c739f4aa5a680fc0d17d1500bc3f987e5fdf8b3984f4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "647ddbb8733d2ab935925356", + "sourceDigest": "257b0c52a69045101122e56e770190f9e02638fb3bfc6d95c316c3d2b5a8f3e4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "647ddbcfeafb6dd17a28869b", + "sourceDigest": "dc5415ac9ecf49f97d4fdc0456cf049d11629a47c90efe50d91a9155ccd86c0f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "647ddbf6eafb6dd17a28869c", + "sourceDigest": "40747f9902a51e099db526363f1b23e2557f5bd3fa737bf639e30e4b497d4373", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64b780578973e285ed4e5e0c", + "sourceDigest": "e19f7f7a25f54d3da32a623d8303cf6c5a22f148c2b279c4cb86847b60397a94", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 5, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "64b7866cf1af57b472231ca8", + "sourceDigest": "5258c22516706d1950b320827c0d64d922d1311a7d833e697462962bbe022dd0", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "64b78a7ef1af57b472231ca9", + "sourceDigest": "0a8c4d835a87078a2d77c0046ed59a4351e2de805e0a0cee076efc7cd661c819", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64b78b20f1af57b472231caa", + "sourceDigest": "a7e2e4b03f79572706f93e26135c2dd832d6714a5f0d5ec534869e55f50ebe4f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64b78beef1af57b472231cac", + "sourceDigest": "dab041442ce352a5f7d81871371b4b04cf2eb99dec8dc3d849c626a96979ff3f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "transpose-only-body-auto-width", + "verification": "getColWidth" + }, + { + "id": "64b899a4dc862dee5aa013ff", + "sourceDigest": "1b77f941c133d4996ef3c5d3b9f07e8234d421c3b853b58748b7f5ff9062c67c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64b9ec8fe563e8374f45e68b", + "sourceDigest": "01adae7ac395b031058f13df87073e5c8e81a78f11c199b24766f0122a072886", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64b9ef89bd5c995da3237575", + "sourceDigest": "0d98d759334fa656cd994718ddfc63616cea505c4ee484485b1e6365829a9eb9", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "64b9f05724402a7e07da8e3b", + "sourceDigest": "6e9e55333d72b0546fb70c6fed813b3f5e03935fe9b9051ab87a55a279be8d3b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 3, + "optionSignals": [ + "indicatorsAsCol", + "legends", + "brush" + ], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "64b9f06824402a7e07da8e3c", + "sourceDigest": "ef9876381c4f9c8dd6e12708f3cfef618ca774369d48295cba57284e68cbc1a9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-limit-max-auto-width", + "verification": "getColWidth" + }, + { + "id": "64b9f13dbd5c995da3237576", + "sourceDigest": "9343d4e4ba37247e94d5da34490bfce2d40d4ab52d8b95aade36181896789ccf", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64bdfcd05134109a76ccddd3", + "sourceDigest": "69c05b33b5579dcc8a565b94805718d59ca9e52e47445376c84a2b13d0cf053b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64bdfd775134109a76ccddd4", + "sourceDigest": "2a1ce735c05a31eb3070761f30e4266f57d8c2d1d2cc36ac12265fc4562ad10a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "autoFillHeight" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64bdff855134109a76ccddd7", + "sourceDigest": "bfc04fbf4a121ded3d8ddeca59334fb4afbf1078c1ae1a1ae874974b1a9baca8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64bdffc65134109a76ccddd8", + "sourceDigest": "9fcf4bf1034cca98f451e6612034b47294ff0690cfe00e88156098622bc638bb", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64be00875134109a76ccdddb", + "sourceDigest": "11a84815d67a6b107b0898a8b46138c84fd1861b5fba8338a4171c6b8dacbef3", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64be00db5134109a76ccdddc", + "sourceDigest": "8a0f5d51a5588b94e4288369d995556850a793e27c2001cd3fb90021074b5b3c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "heightMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64be017a5134109a76ccdddd", + "sourceDigest": "10f88b5d8bd8d3ccebe42708fdd41b2f6869d83a8c50c9af5bfb8e3f341356c5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "heightMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64c8fd3c6a0e890080b1aff6", + "sourceDigest": "272754dfa13705c4c9df3d64b92a6454d5145d93bec62d96f93779aff4b701e6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "heightMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64ca489ff22710ecb1c7e6fd", + "sourceDigest": "1e506ee97b1a465be0b667f6b80ea0570686126e3ff64bfdc4f5ad141d9167a9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64ca48f3f22710ecb1c7e6fe", + "sourceDigest": "a944213abeb7e43b818b54eebc59e64e19a98831e083804625bafda2c5bc3de9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "legends" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64d9ce2b064f3d06175b0f25", + "sourceDigest": "de8407dc2b1b7ae99583665d22e60c24d908faeddda0c38c92abe0d7e58c8e21", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "autoFillWidth", + "widthMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64d9cec3064f3d06175b0f26", + "sourceDigest": "0a77e4ad08d36a0556762f1b4551949199b3ad616fe51553338959664d4c6651", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "heightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64e869fd707420a88d0e6932", + "sourceDigest": "9c19a550166f85ae7e8db7e50eff2620b83c2592eccca0bc6426a579305f8fdf", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64ed8e7ed4858ce3fbd85ad5", + "sourceDigest": "b01a7278780471aa331aee9d9bff3776cd966e4717bfb8376e102a0e66de9b4b", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64ed8ed1d4858ce3fbd85ad6", + "sourceDigest": "29c5cd13436642605352757069c8bb167764eada63dd44ca5d667e134dc213c5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64ed8f3ed4858ce3fbd85ad7", + "sourceDigest": "b90653f8d141c964974f120635905b0714614f766bb0f9f52ae76117406984f4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64f5b9690f4df6126e128057", + "sourceDigest": "e4c9ca9d78a648f697e1b0116fe02db2e7d238760e4e0dcca5d7bc86e046ce1d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64f6cb47c380c3009a3e7e62", + "sourceDigest": "08ebc79d2f06705b3a3152e64dd21d5a8447bf7031289d2bd805b3756e9684ba", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64f7d8862937835bd5c893fa", + "sourceDigest": "5df1acdd056cc66c5407656809a20eb82d145cda84ebe63fab1c9fafab4c3ecc", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "pagination", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64f820a67d8f46008b2df45f", + "sourceDigest": "9994147130ecb7905d6211cce7954d78407cea89874aba003212decdf696bab8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "getCellValue", + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "64fa93512c50118f1f4dfe3c", + "sourceDigest": "ba41acd1e15d50a5b2b002ab474c2c581ff204b0a9cef01a06b0dc3556c90c44", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "frozenColCount", + "indicatorsAsCol" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64fa94442c50118f1f4dfe3d", + "sourceDigest": "fa8138164076cc00c0da522a681b3b66f435dd8e56593fb8a5106b1f604f19c4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount", + "indicatorsAsCol" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64fae5b614f81970d8db554a", + "sourceDigest": "be4341809514c7f82f894119f65b28c87dd980bdb30e12063694f51035edaa9e", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64fe83211754d74d66e96284", + "sourceDigest": "b1e2d1f5077fa59cfeb3a376e4b3636cec30b6bf871612e36b7476b7c09ff466", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "64fe8892bf9b5176ccd51408", + "sourceDigest": "8a6907768ef592ff6fd8008efbcebcdf68fb386832e13630cf97778f51a22614", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6500046296294da1e9b882fc", + "sourceDigest": "c2892e8e38abb86ed1d6f5f76e9ccaaa19be44484d3480d6d87c2c40e980c380", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "legends" + ], + "methodSignals": [ + "on" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "650195bdced2a800826bfff1", + "sourceDigest": "2a4c90905a00c6edad40f8accaeb476f60dee6391b5369a0f53da39a4f618b04", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65027716138232a1b6ffc39d", + "sourceDigest": "0b539de499b2148158cad19bfa1e32f63bdbf0d4568143ed7743a995ea7ef032", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "autoFillWidth", + "autoFillHeight", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "650835828f73d6fa71c7ef58", + "sourceDigest": "369542d4f2c0888a1533ad1504b2cafda837e975417b897b42f7caa93580acd8", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "650bb5840927bc458fdcef4f", + "sourceDigest": "098d890f475472c7d3aa077e42b4f01c46bc6317a42f75e12f14212be95e1968", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6524ffcaa876fe243b5148e9", + "sourceDigest": "0724312f4b8e9bc26d9e342f18850791a9b69d24915303a1f0676281a4a300b2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "autoFillWidth", + "autoFillHeight", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "652528d0a876fe243b51492b", + "sourceDigest": "51b7f7dd3aa80539f34d6754bf4b738f30cc3d2222f207ca75f1788d4124a393", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "6525294ba876fe243b51492c", + "sourceDigest": "633f1ee5da7e72db2452e555547121654cba96b48802b11f25a18ea75f6b21b3", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "652605dda876fe243b514956", + "sourceDigest": "b09db23ae56e8389761a7f5571efae2fb06f33715cbb80514fe518e6c9f14922", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65265a82b8b61fb2c4781aef", + "sourceDigest": "2d6e94cfa39f8437afc26a0d37e0db9420fefed93f2943556c052e530ba15b23", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65279aa795c0cdbd788cf15f", + "sourceDigest": "10315153ffacb0e57084330463c12a0976857bbbe5966d94d72366ca58df2388", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6527ac0695c0cdbd788cf17d", + "sourceDigest": "93317dee1c281151570b7880cdae8500120380a03bb999c68c035c87f15c38cf", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "autoFillHeight", + "widthMode", + "heightMode", + "frozenColCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "652cf14751d9f60a3c5cb89b", + "sourceDigest": "8a44df3c1fbdc4d3305d177f975ba3c493337bb614aa7bf697dfe803be9db954", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "652cf45351d9f60a3c5cb89d", + "sourceDigest": "c7e7a47eee28563b7f059a8fd96fda70b275da15ad462067b533d7445af4e964", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "652d0e6b52abb1c00ef7dd7e", + "sourceDigest": "e0a11cdc511167342c1281f639617bc8e388b7884584807d3c9289ac1af926d1", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "652df00752abb1c00ef7dda5", + "sourceDigest": "c02a46bc876323419d3252984dd2619a04b8bfc80fb11685f727968b63f3d6a6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "652df8a452abb1c00ef7ddb5", + "sourceDigest": "55ee0743d8dd4e8a7e177114ff0af802359e6fbcb2447f539338280a1a2e7797", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "652e01c41dd15a4ab522f751", + "sourceDigest": "33f4a46bcaec677c986b9a92b507bbc3a77837afe6625a60c2f40ed104d61bf4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6530df274b150fb4db03fb1d", + "sourceDigest": "d5c314e833b203a0ad8b0e68795f1206000ee038cf2f5418339ebc0479dcf3c8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6530e2138632117ed798a22c", + "sourceDigest": "a7e2e4b03f79572706f93e26135c2dd832d6714a5f0d5ec534869e55f50ebe4f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6531008b8632117ed798a26b", + "sourceDigest": "f1c0d6ecd3db70c62794a27056fdf2dc6ca0eda64016012b9a9dbfc73ddabad3", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "customLayout" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "653102ad8632117ed798a270", + "sourceDigest": "be09e73cee29e936aae1d28da64359d7013e723bc866d2118c1320f7849103b3", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65322e87159a621b655d9eb9", + "sourceDigest": "63caa525a6d1c246d27e5065c38bca669e7aa70405f9a716133ea3fe0e3fcfbe", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6532320388cd1012fefa741c", + "sourceDigest": "96362f79a82ce0d8fb981423a1939524e2c7640ee72972323947c708dc8863f0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "autoFillWidth", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "653249d776bd2d82b5ce5e67", + "sourceDigest": "b89a82076afdde8e8ef8b78b28ae4b82827edf120234f43e6b1b81b82ec3114b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "cellType", + "indicatorsAsCol", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "653649cb173c354c242a7c4e", + "sourceDigest": "6a5320c34a4c583e4d0515d2120c68213ec0846a28cb57e9b2c802e62326b0a2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "65364a57173c354c242a7c4f", + "sourceDigest": "ffb42ee64757baf6b7449370f44fc7c77a26d197f1d7b3ac3c0162aedded2114", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "65365114173c354c242a7c5a", + "sourceDigest": "b638a6874e6f55c9de57f605b599266f5799ffbba0bb5791cb531a0ac4d0fb88", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "65365140173c354c242a7c5b", + "sourceDigest": "9ad214f48f3992c9752b8c205633fa6375200fab0f2739ca47085315d7148d49", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "65388933159a621b655d9f6a", + "sourceDigest": "4a1c7cfe9ced3d703e7f6ac425976a4e9afd741cf9f529ab42e3db215cd8bfe5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [ + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "653b2f891053b2a37d5dc9b9", + "sourceDigest": "cc8c95f3bda86001ca09e3623f1512b194ce4b40b7f8cbe21ea2c5ebe407ab6b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6540b514f95bdcf7c340d701", + "sourceDigest": "23f20c824b531105cb64b5ade056d299dd001ebaec91af9b151cfebd4468a2c8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "autoFillWidth", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6540b960f95bdcf7c340d702", + "sourceDigest": "dbb77f607f6653e2f95bf8448966d70c644487e8988937f9b67f8d0955f787db", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "autoFillWidth", + "autoFillHeight", + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6541cdd044dadd6b7cb441cd", + "sourceDigest": "1e1da6a7a26db7aad6534b2789d0d22ff1f788df40585ecb134ef58dddd8f95a", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "area" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6541ecf501e33ad70dc01e38", + "sourceDigest": "6f6cc8561efbc83a07dbce96d1afbcdcb0f2b8cdf80a0d7bec71fa28f1792c4b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "654311df0dc4c5635dc0d9ee", + "sourceDigest": "118aeb88f2da7e06c9d9114620e635fc8ca567b5e38a2ae7f5eb0ae98174aaf8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "654348a6b3dae69746d08701", + "sourceDigest": "0708bfd4782b2b8f4d2d549708dfccc83178e9fbbcc7e85c6b817ad4c792393d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "frozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65434afd0f2472008d41149f", + "sourceDigest": "68052434e540d211735ade0664a1b03625950a60a229030b7517c07f74bb44af", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortState", + "widthMode" + ], + "methodSignals": [ + "on" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6544ad1a4280163c75d7fa98", + "sourceDigest": "a9055bc8a356b75ac9ea7889825fbd26184538e3380e4eda98d9504d032388ed", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "disableSelect", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6544b3b14280163c75d7fa9b", + "sourceDigest": "20b29dcf09e4bedecdd37824aa8057d21a0c3ef14933ccc04827e2d930eb8016", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6548820a74e16908bc0462af", + "sourceDigest": "0ea08c5faa88292defe42b08f4fa9402da15db6d1f08927eb284f346349f6269", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65531b6c50997c335fecfcc8", + "sourceDigest": "4ad189ec1225a4d3060f35ff30112f88988b43039c0068ba765678e4244f0833", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6554a1059dabd71aa3845b5b", + "sourceDigest": "6fa6d7de9b0f53026c3ee06c01882e9a71a7a81faba1bc46a0e5333114e1cc09", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 3, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6554a2d39dabd71aa3845b5d", + "sourceDigest": "d82d96e522ab7b5ad23f637b57482ebf4a7de9c870b999dbe28191ef73c08f52", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6555c2b69dabd71aa3845baa", + "sourceDigest": "227027fc197bbd0ed4de844aa171c66ec337b7798d8c494114aee56fcae3bb1e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6555e6399dabd71aa3845bb7", + "sourceDigest": "4aad16ee12ecc25bffbfe34ef0345543ec74d0514126665c3aad34b1d5330801", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6555f4339dabd71aa3845bb9", + "sourceDigest": "f3f056d8c5069e9a51ee3119c1769e23cfb32a864a9da6904f5cd3fce087e231", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6556050183c71200999f1f0c", + "sourceDigest": "9894cea9f613e77fc8f8c96b5a0e1623e78bf7d173333a0b049ba73153eb5f4f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6559c6a238a83fc5d230159e", + "sourceDigest": "3323ef7277188cccb77a3a4d32c213455e5061e708c4a69a89db24d54fecfbd0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "autoFillHeight" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6559c76e38a83fc5d23015a1", + "sourceDigest": "188b429c5fd18e0247662496d36b6ac03243cb1155b54e3215103e3ab78aea35", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "autoFillHeight", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6559c7c838a83fc5d23015a4", + "sourceDigest": "0524351df695c5891b9d600cc44f07ec9187ed359bae14defe5dd0bb856328b0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "autoFillHeight" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "migrated", + "priority": null, + "localCase": "layout-limit-max-auto-width", + "verification": "getColWidth" + }, + { + "id": "655b14d48ff2e4008d53a9b1", + "sourceDigest": "de0dfce98c86d3a472f7030194d375b822577f9f4f79352c01a6bcf5cdc9b1bb", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "655dc52112c3a41900817f36", + "sourceDigest": "0b2d5116106172965f51db0c0072127afc880c71dec18bbab585e30ae35b3ead", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "656582287bb49c240fa99c7a", + "sourceDigest": "c488595b6bb8a3821166f6d643b9d6418393a8a2f42cff17ee5ddaae73d03d8b", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6565b5717bb49c240fa99ccd", + "sourceDigest": "a17708f7fa951533ae7051fe3ca1cb3d4472cc9de7d1bc295d5d4c790bf0b186", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6565d1fe4c6c1a77d0efcc77", + "sourceDigest": "8ce18fb0473d73bbcfb0ba92521b740cc871b027d98db54152046a860db6d9aa", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6567f8ac66541d99f6bdfc3e", + "sourceDigest": "3ee7abdfa385add8d873f10209aecd268e46c52aa99a4b9829da833ab08314a9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6567fc0a66541d99f6bdfc42", + "sourceDigest": "118aeb88f2da7e06c9d9114620e635fc8ca567b5e38a2ae7f5eb0ae98174aaf8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6568014a66541d99f6bdfc4d", + "sourceDigest": "b2a3fe2dec3401d3b4e03a6ceaa351f000803db1289bbfe55556b815e38c5889", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "656803b766541d99f6bdfc51", + "sourceDigest": "173574ab6b2a16846f01038f39446bb215935bb35893423b63c28c902b3f7658", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "customMergeCell" + ], + "methodSignals": [ + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656987434c3611faee9b1a93", + "sourceDigest": "9b430ce0feec95f55a5d7d3a12d393bc5c98bc5f49122bf063da593efb4636a3", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65698a264c3611faee9b1a94", + "sourceDigest": "e6a86821836c7719ebf0b24799271d58ae71174089f5ec42f87771d55a4f681a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65698aed4c3611faee9b1a9b", + "sourceDigest": "560251d275467d1af5ed5302099c1c769ff808e2c843eb4399912c2c29999781", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6569af794c3611faee9b1ac4", + "sourceDigest": "242139e55363019b6a47531b21d9484113eb7586a241da8ceb058c78a4274183", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d86374c3611faee9b1b25", + "sourceDigest": "1b8de515bd5095dc3ccccccae0a8508bb36d0867239d4ab5d08212f7ed42a4a5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecord", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d91704c3611faee9b1b2d", + "sourceDigest": "107937e235f70c763bf183ce770cd83eb0fa367aadae7295570d402201c3a932", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d92cf4c3611faee9b1b2f", + "sourceDigest": "1d6c70c1eb755e768d4b663bbac7211fad46311267e4b10f7973a8adab3617fc", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d96194c3611faee9b1b31", + "sourceDigest": "04a6249eac7019af250e816d1c7678e34d69a48341769449af997b303a1a516c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d96c1eb24adef19a3a6d6", + "sourceDigest": "bded415e17c7779ddc5f4d8bb154df45ec512db0fb869c627a4514aa7492adb1", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656d99024c3611faee9b1b32", + "sourceDigest": "abad715874fc8762bccedf6c19dea330b4b9f16e4fd0febad4778385831a26fd", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656da0e04c3611faee9b1b34", + "sourceDigest": "07b46c7dc5800a6e926d41a5c87604baf01d88b2b34b785f89f34fcb1fdf4065", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656da1a04c3611faee9b1b35", + "sourceDigest": "84bd143834d662a6d7e821c1b632c4ef34c1a44014da3328969cc194eb1bba9a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656da1fa4c3611faee9b1b36", + "sourceDigest": "c8a30a2068b30ff4966c754840fac1538b73ad5afd1f518a135916b5ad0ebece", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656daa084c3611faee9b1b3b", + "sourceDigest": "479f8ab01207d174871e8c661eae713b913b83db7b055558979f895094e043dc", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "selectCells", + "setRecords", + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656daeb04c3611faee9b1b3c", + "sourceDigest": "2280f3d91e0472b636044ca29451f257d6fafa5665f3d8fb2329c02ccf74c21f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "selectCells", + "setRecords", + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "656dba6e4c3611faee9b1b51", + "sourceDigest": "39c7c5eb4bc1cfe6f3a60be1dafc31f7b0f817708eae8d76d23d6fbc4cfecd71", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "addRecord", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6570142144052e47f77c2925", + "sourceDigest": "3f920fd090d334c4bc7fe1b82dae8923f1ae3c1e5266e5c97cb6e3d291c54c56", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "657014a044052e47f77c2926", + "sourceDigest": "9714483f3f4cfc9d883c089f116fb539e0a9b6d6e49cc3776c38028ec4a289eb", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65701eb144052e47f77c2933", + "sourceDigest": "2e5391e1a918f7c35649a78c97f3fed6c9567e7d4780d1df27e0a55462ec25a8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "autoFillWidth" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6570227544052e47f77c293b", + "sourceDigest": "4ee8571d514f5dd9277c2bce7e7e8dc672f84ba3407d39805bf8c5167345e01c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "autoFillWidth" + ], + "methodSignals": [ + "setRecords", + "updateOption" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6570253344052e47f77c293e", + "sourceDigest": "53a42a7375066391c958d63873db9d2b6dcdb8d1110486fe4988e3dcabbda696", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6570258344052e47f77c293f", + "sourceDigest": "4f651fe8ef59b794a5a5078bc2df9c92be82a45cd813fba9b17acab2358a854d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "657068b644052e47f77c2976", + "sourceDigest": "736f3d39d7c90d4d82c63d599610ff322d9b8a729dedb6759ce3a63e3b826bdf", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "657068fc44052e47f77c2977", + "sourceDigest": "c9d74009022f66e2d95590f7f9f8cb79bb354a94aee64a9cb5b6fe0fb5fe55be", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "deleteRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6571638f44052e47f77c298c", + "sourceDigest": "a1e17f86949e82c92d2977ae67ecd6b3b23ca555686d37fb99c36c65fd984011", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "657163e944052e47f77c298d", + "sourceDigest": "24a919d4d0ab4490c092233aff374c1ce07126df311058aac943e8f6f0cda094", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "deleteRecords", + "setRecords", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "657191a244052e47f77c299e", + "sourceDigest": "00c242e5aad417c1789d3df92d76c4a03104d542c1d10789067e0083b726916e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6571b6fe44052e47f77c29a8", + "sourceDigest": "1d67b518160d917dd6775b63c9d22872d3b5a3c6b87fe1be1f1ae6f584f8d49f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "selectCell", + "setRecords", + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6572914344052e47f77c29bf", + "sourceDigest": "5399ed0b73e0124b53e8778d59256b07a63aabee7ae22fb8ebb04d16e9459008", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6572d31d55fadf4f41c7499c", + "sourceDigest": "f798c2b1ec259a1d4d89df649c95ee24c5c6a6378f2bff27ebb0afc2c822f694", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6572d47855fadf4f41c7499d", + "sourceDigest": "272b2338d73a9d8a18a5223022f761a9ece41c006e5f5c16abcafd4ce5b72ca5", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6576acf99196f8117d093511", + "sourceDigest": "b8ac907f29b10cf538dee3ee199134ca3f70b4a459efb14de69fd25a7f20dbd6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6576b5139196f8117d093512", + "sourceDigest": "8cfe52a9424fe1350bffd3a0abca90ab1ea50db59fc3439ed2c609052a23ffa4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6576d15b9196f8117d093520", + "sourceDigest": "05475d28ad4c3da31cddac04e3a0fe51325961cceefd194aec68228645bb0790", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65794bd87aaccfc82db37e98", + "sourceDigest": "99835b3a00c51f9c65e700d290e48d3cbcb76670c5cafcdfc45cd87c058fd5d8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "heightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6581698ceab07e0091708bab", + "sourceDigest": "8afa7c4cd7dd22c44a27da3874c8042e63e4f42205e0bbca00cd8766187be724", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "sortRules", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65817239eab07e0091708bb8", + "sourceDigest": "1ae61432a8e5d515d5c598b8d4e353cdb93af318ae88c527b2dff568c0375ad7", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658401ca807cf6008d99baa1", + "sourceDigest": "5d572cf5bffac7b197dc1796f1819c9a2fb019b137a3f63ac59daf2ba97ee9c9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658404be807cf6008d99baa6", + "sourceDigest": "eabd0062704c454942fffd0b8dbbea8658063eb244b5715471588e464700dfdd", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "widthMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "select", + "disableSelect", + "highlightMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "658406f0807cf6008d99baab", + "sourceDigest": "d9ae1e04586eb69b0539c4b32da9c4b7b799e8676501cbaca6c7a99c175b03a9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "heightMode", + "frozenColCount", + "highlightMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6584086d807cf6008d99baad", + "sourceDigest": "1e8ad08be78b7f8f58d96d2956bda5d4f56491954107c7506859c7b0c82bfed5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658c0a1b9f48b900833db069", + "sourceDigest": "92d6ee213dbce1d2ade951996653d1703428ac99aaa77b51cce03116e973559c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "658ce50d70a7bfed368af60e", + "sourceDigest": "e7c687201d0efc5e5e1838108b5665ebee7119452daacd084510d45956e07314", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658cf04020ffa2008c33eba2", + "sourceDigest": "b6e14ae0541b298a846f38f1f66951c218ddfa52c608ab3895f74ca1b053e34c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "pagination", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "658d566a20ffa2008c33ebf1", + "sourceDigest": "1593d12730815e51df19a09774c3ef80560c62f374628fcba70cd8df4ca2b276", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "disableSelect", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658d56ae20ffa2008c33ebf4", + "sourceDigest": "43575419fe21eaa943a8ba9b72ccc5b3115814570603b669cd57ef904829dd83", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "widthMode", + "select", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "658e984a20ffa2008c33ec28", + "sourceDigest": "52fdd58cb6144746f3fdd04c241fee1a84afd4209b74771f137d5a6fa5e31aed", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "658e9bdfad274f1e6d6d8964", + "sourceDigest": "0aa7d185e2bab3406ee9dec00ef9bf7ee06ce98d7d423e4cb89295ccd09541f7", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6593afc1c2aa2c00881fa911", + "sourceDigest": "09d0ee73950b7aef0aa67a4eed17bac1bcef4b20aafe2795a17d08cd019c3394", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6593ff4c0225f4008cc2b833", + "sourceDigest": "1130e6360b07f1484f42791eb811f5464997f42e09ddb13e942e5a24a7e0c79c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6594ca3134793a2f0e51ac63", + "sourceDigest": "245cadeb8bc28265429ccb5e19f1494726d2a4ee64d82893995e549840b48c4f", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "cellType", + "rightFrozenColCount" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "common", + "line" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65963357c3cfff93ba49edd6", + "sourceDigest": "52c0ce65fda58c6c90c9cb342f06edbdf8a420d3813994a2593c3dac6f916c11", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6596a56ec0a639008d8be557", + "sourceDigest": "7737706de1769b757fbb6d5de1020374a3ad7ee8a296de8726d03c65a24279ac", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6597c161c0a639008d8be583", + "sourceDigest": "5df89defe7625bfc5f61085660d5b49fe29721c313aab3993472897c61abff93", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "customLayout", + "cellType", + "rightFrozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6597c3d7c0a639008d8be585", + "sourceDigest": "d5dccb372b1f2d15196c83863670f2ec29e2a9606858155ac6cb09f1872c3f55", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "customLayout", + "cellType", + "rightFrozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6597f0c5c0a639008d8be59c", + "sourceDigest": "3f311d980701164dc17d4339d96a965435abeb81e901dc53b98ffb1979223fdb", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "changeCellValues", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "659e667c6040570085cd3eea", + "sourceDigest": "d8273e4fb2c3776a9d6912ea8e76f18a12a9d1052a5b17711edf6896c799d563", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "659e66ee6dc8940098194926", + "sourceDigest": "e2288dd700a8ca105b0bf2d5c7a4b2b7bad201b06f1e68c62e63913f5c1a7a9c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "659fac0e613711de69e3859e", + "sourceDigest": "68c0dc1d258c393c1777b4ea710f15317fcd7cf4f49bf0de0ac9edeafb68baa9", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "autoFillWidth", + "customLayout", + "cellType", + "rightFrozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "659fd5ef613711de69e385b9", + "sourceDigest": "5973f88937c5f1d49ebaff34c948390f3d49e079a3d648f85f680895e6535376", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "autoFillWidth", + "customLayout", + "cellType", + "rightFrozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "65a112755c6d60008335ece0", + "sourceDigest": "9a2e619a47213fe836890a232ff210f4365cf815951b89ed23243cbe027bf36a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "autoFillWidth", + "widthMode", + "cellType", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65a118f75c6d60008335ece1", + "sourceDigest": "922bf94b998a01d30975d1b6d85dde29c8db942d762c713f7aa14b9eb8531268", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "autoFillWidth", + "widthMode", + "cellType", + "frozenColCount", + "rightFrozenColCount", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65a501e1d0814f00842d407c", + "sourceDigest": "6c76e619449254e46a8b417695d3ebd4966c8bd86b12339b2d79e3950767f224", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "customMergeCell" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65a66b0f518457638fa485bd", + "sourceDigest": "2f65d56f0346f560003346500446fd18853d0e669787695ea6a39d5c1e2308e4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "pie" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65a66b94518457638fa485be", + "sourceDigest": "578ab58a178613608e74a5c5f92519988ca9d8123fff901eff2585c3c986a0da", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [ + "pie" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65a66c5c518457638fa485bf", + "sourceDigest": "c9cd3ac041b220ae60b0593ec09ec5a2078f6b5a256bad62aed4b77d6f8c8902", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "pie" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65a8ebbeabe49a7d3c712553", + "sourceDigest": "e1ea91b241c50ba6009e1c5f2776565cd58b65441424221f912eb78f95d9d6ef", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "bottomFrozenRowCount" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65a8ec24abe49a7d3c712555", + "sourceDigest": "312eeeaad94546552ad9ba6d231b00ce5ad74c2d308a374de54037b50aa5858d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "addRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65a9e004ebac688c39e91e22", + "sourceDigest": "9badcf0464f9c24860db1777b27f15b493f1ebbd9f3d918c1a9cd414fe6e2b20", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords", + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65aa128ece203f0089b9f7bc", + "sourceDigest": "7ee9f53c5dcf021d352c18e7a1f1cee8adaa5a1583aa668b49b9eca3cad9cfd4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecord" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65aa12f1ebac688c39e91e42", + "sourceDigest": "5887cc5685d78706805f009e1aaba8f70994945d01f1efe7c1e8b0be2804b612", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecord", + "addRecords", + "deleteRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65aa157febac688c39e91e46", + "sourceDigest": "858eec4032038b7ca6527c0e24b8f56fb31f63d82c7662d4289f7d9ea0dab305", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords", + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65aa46730cef8825bb267d9a", + "sourceDigest": "2aaeb1cce7bdb7c9938e03ea8ed319dcd0c905a3337d075bf59513ccad64dc3c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "dragHeaderMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65ae4071366fb000953feeaa", + "sourceDigest": "1eb351a00e3674fe4d17b1274c2924b0fa3c22dd16bcdc0632b0fff4e80e1db5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65ae4297366fb000953feeac", + "sourceDigest": "e5f45cdaa2249b1333b04aaaff7f288c943bcef1e555ceba1343b8fde8986353", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65ae4544366fb000953feeb1", + "sourceDigest": "b9057cf3dc7728fdab36db808c3b8016d7caea9dff3f246fc364f06ada70629b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "migrated", + "priority": null, + "localCase": "frozen-drag-disabled", + "verification": "getHeaderField + frozenColCount" + }, + { + "id": "65ae4667366fb000953feeb4", + "sourceDigest": "dd05e42e9fcea8a5370ed37e50f24c36200e13cf6231fe200f1c17b4be6d1a5d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "migrated", + "priority": null, + "localCase": "frozen-drag-adjust-count", + "verification": "getHeaderField + frozenColCount" + }, + { + "id": "65af6e6906085f008cf8f85f", + "sourceDigest": "bdb545a9ff1de2ba3dc094462a9c2cbe13713f9ff09fc90174acdc615495f803", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "updateColumns" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65b2059f06085f008cf8f8f9", + "sourceDigest": "e20365509e2df39fb0a5cc205edf0fdbf02e99e249148211727aaa1b5c19dbe0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65b381c5de2002008ae46bbf", + "sourceDigest": "e5f45cdaa2249b1333b04aaaff7f288c943bcef1e555ceba1343b8fde8986353", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65b388fade2002008ae46bc7", + "sourceDigest": "9f4e32cf6806968f72c74110245d4a1937668ee70ab1c4ac4727a8d9f977cfcd", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65b717b2de2002008ae46bc9", + "sourceDigest": "b896f6d0408a9fdab88f9e677e133e06324abac27338425e72c91ed467f1fa20", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65b8764cecbd1000ab63334c", + "sourceDigest": "dbd50e67d43e284638ea0bb4dc5b98c3fbdc06e0bd945d01a731f0acce084bba", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65b8a178de2002008ae46be7", + "sourceDigest": "85d76f85004a26f2992b20b484c4faa322f5ac6dffd9b21728c2e75817a88400", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [ + "on", + "updateColumns" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65bdcd76ce3320008eecf684", + "sourceDigest": "fceedc9a879c1d30944a58d7e83803a43de6a35bf5d713d38a5ca6d795fc40e1", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65be113cce3320008eecf686", + "sourceDigest": "1098d8d1338334bfabddea1bd730c59ea2ec5743c558c78177a6fb83383ff7b4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65c088a197cc3d008de5b484", + "sourceDigest": "24f461f0956a2570b95708eae55e0bfe4cf51a1dd36f765d5d7103d192069cc5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65c0951b97cc3d008de5b48c", + "sourceDigest": "1e588a8ff025271f017424e433413c1c7b2e6419a1cdadeab419a836d3f995b7", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65c0983d97cc3d008de5b495", + "sourceDigest": "232e6f5b301e0eafe15dc87bd4d265af3dfa9a5728d0b57f5cb07da02ccd2e62", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65c09b2d97cc3d008de5b499", + "sourceDigest": "f6a4cbf35bcf10773e176373d60a0970a59999c824dbb957bda6dfb1030387e3", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65c1ce3f97cc3d008de5b4b9", + "sourceDigest": "37ff4490fc7a0d2472693457e0215b0565002bbf63744bc059509148255172b6", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "customMergeCell" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65c4729697cc3d008de5b55c", + "sourceDigest": "368904fe6598cf3c249109de8283d32bdbda668fa389ce7a9179ba28a7eecfb0", + "family": "list-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65d45c7a97cc3d008de5b576", + "sourceDigest": "edd51603be3b7382207c0855b103a1cd497bd9b38d6867abd47c3122ad3a8e3d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "updateColumns" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65d4948797cc3d008de5b593", + "sourceDigest": "1f73a44163ecd6adb46ee00c043d1885393f53636a4352cf1c9ea77e49141cc4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "cellType", + "transpose", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "scatter" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65d572a597cc3d008de5b5a4", + "sourceDigest": "9b4b0c78ec66233caee63efa1b6b516cad31ac931a94e5a3b867c55f49de5c1e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "select", + "disableSelect", + "markLine" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65d59c5d97cc3d008de5b5a7", + "sourceDigest": "ef228c0576131a018825fbcdac8dc00157419f8917d7b043f43f0db540c2ede8", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "customMergeCell", + "cellType", + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "getCellOriginValue" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "65dc3ddddb5fe000ad96fd7d", + "sourceDigest": "8125cdc2a58031fbdf54e4229362f1746d2380a38a880ad9f52dd4815a71c082", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65dc3eafdb5fe000ad96fd7e", + "sourceDigest": "8788c3dc724da2e6c7360fd5c07c55548141d2c291f8ee7e1e3d99715b519b7e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65dc4029db5fe000ad96fd7f", + "sourceDigest": "c5378eb488d2284192a9e78f9f1a0a168574275a1163614c2398e0c5bad9ec7c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "transpose-only-body-auto-width", + "verification": "getColWidth" + }, + { + "id": "65dc497adb5fe000ad96fd81", + "sourceDigest": "853c5944c8481834a649abf6fff56e01fa8da4d9232e7cd5df5a0f6c5e6bd595", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "cellType", + "select", + "indicatorsAsCol", + "markLine", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65e003cb1baf7300adb862e6", + "sourceDigest": "5b35b5c0fee154862c6361677d98f7b141103cbf30a3712f5bd8ab705c19618a", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "widthMode", + "heightMode", + "customLayout", + "cellType", + "frozenColCount", + "rightFrozenColCount", + "select", + "disableSelect", + "highlightMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "65e0291d1baf7300adb862f7", + "sourceDigest": "ff76af628d7c3b12e22b27511dc4b35e265449385243af9c30bb6f01c12d5251", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortState", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecordChildren", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e5bb5b603de700d1d8b9e0", + "sourceDigest": "205bfb1a95701026127fdc44b05a03cb12c629a972363aac33ee37c234d2b17b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "changeCellValues", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e69335603de700d1d8b9e6", + "sourceDigest": "ceb5e0c37c35683384d4d55331a471aea1bac764e3e06f1ee7832ebb8bada2aa", + "family": "list-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "editor" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65e6d237603de700d1d8ba04", + "sourceDigest": "6127c54718de8b3b8738257ac7129a6df19d792e2bc6d94e414eb2a7c05cbf1b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e6de57603de700d1d8ba06", + "sourceDigest": "f0b3b93f29d783dfe3e665464126188c0858b928d41569f1a2bd6ea3c81fdc17", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e6ee9b686c6d00b99d7962", + "sourceDigest": "bccfee19e0f88d72226ad7f0cc6fa0d2d3c36cd8fa799c3fa4af0f3e611f9c9f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e7d082603de700d1d8ba3c", + "sourceDigest": "c991c48337d2b6be84510b9d734e3386b5942d43594331dfe633d591c2ac005c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "editor", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "changeCellValues", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65e7d4da603de700d1d8ba3d", + "sourceDigest": "05e37116dbe3515b70e588c54ce7a4700899222450c18444c48b4ea8ac9abbc8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "pagination" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "65ea7cf27c3a0c00c99f2cd1", + "sourceDigest": "2c62bdb07185a4cfe769f0f4f7246550d4dd11dc28eb3a6d8ea3a68bdc12e54b", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "dragHeaderMode", + "widthMode", + "heightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f1260b7c3a0c00c99f2dad", + "sourceDigest": "c86bf94285b40bbc1d650683b8b1309bc4d24d7e89656b7502cbf3a575cbe2dd", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f3f85d7c3a0c00c99f2e1f", + "sourceDigest": "e7f469c2d84fcad5f8f6924446616eece047c71eebdd6ddc8a22351df1bc548c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f3f8e21baf7300adb8633f", + "sourceDigest": "d2a8da0d89deac447be87997a6ab363c19215afe363f4d3c588bfae0a7bf83f3", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "widthMode", + "rowSeriesNumber", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f3faab7c3a0c00c99f2e20", + "sourceDigest": "227238bcc1ed0a5bd0ea80d6ce75381051c6ddf79b6a3177834d3da96127d90c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "sortState", + "dragHeaderMode", + "dragOrder", + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "on", + "setRecordChildren" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f416ac7c3a0c00c99f2e21", + "sourceDigest": "0e2844f9f4a721f1d3f8d82eef57332944b8eb4f240431ea19c83cfc5c413871", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "showSort", + "pivotSortState", + "dragHeaderMode", + "dragOrder", + "widthMode", + "frozenColCount", + "rowSeriesNumber", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65f416fc7c3a0c00c99f2e22", + "sourceDigest": "e95c233e5197553e315a5580e043575ec13f0a87df65bcf1100edbe5b23097ef", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "widthMode", + "rowSeriesNumber", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "65fabcdc7c3a0c00c99f2e99", + "sourceDigest": "0b7c7b0af3c75d82c269cecf7253aca8ce1f720f762d39a504fdab26c99b3989", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "65fb9f5f7c3a0c00c99f2eb2", + "sourceDigest": "4be941c8c41ae073bc20af427b22ada54d0f085f4c65499532d82301fb175a96", + "family": "list-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "autoFillWidth", + "widthMode", + "heightMode", + "frozenColCount", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "65fc1171603de700d1d8bace", + "sourceDigest": "84bfa23a68ebebbb01aed5b8d22137aa2a806aaf4152bdb6106b884772808b7f", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "rowExpandLevel", + "showSort", + "widthMode", + "heightMode", + "select", + "headerSelectMode", + "highlightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "660130103b10c900bdd7d4a1", + "sourceDigest": "5750ff28befb5a215e0d81434cc53c97a7d87803714a6e1d8416ef65a09a0e8f", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 4, + "optionSignals": [ + "showSort", + "fillHandle", + "widthMode", + "editor", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6603e21c3b10c900bdd7d527", + "sourceDigest": "6e1e6d2c9c4202e09ec01dda1ae3cd6e84b7ff49527e40e733692f68efbbeeec", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66055e7ea8fccc00acd37038", + "sourceDigest": "bd9b1dce514e2a6784289766408e9777093b389d14aa81ae561ca0efb0db4b84", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "frozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66055ebca8fccc00acd37039", + "sourceDigest": "81b06f9fb768af46cb1e5d0d0b09f8346b82a8ef3f8e470a02cb27798e6d2caf", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "660bd37186babc00a5d92263", + "sourceDigest": "044361c03f52117a470f33690a5d260be148faeb5a1c882b2bb373981f509af5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "rowExpandLevel", + "dragHeaderMode", + "widthMode", + "heightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "660bd44f86babc00a5d92265", + "sourceDigest": "ba4a1c702146d5979e93bceb37a8584c71c234a2eb3190fd16baf0e83a9125e4", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "rowExpandLevel", + "dragHeaderMode", + "widthMode", + "heightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "660d09e236273600b2b8e9e4", + "sourceDigest": "5313e2ad078b70d0fcfc61a7fa949203d66da0dae5908340d2e1e86b06a716de", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66128a9036273600b2b8ea21", + "sourceDigest": "fc96ce4e5a25624b844ab482cb0e916e85c0afba6c60ed386ac7fec83983410c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66152cf42acd9c00d1c98a6d", + "sourceDigest": "462d68da8ae6634099763a7238ca7ee13313f99e0596c28aab164edbe218bb8a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "sortState", + "autoFillHeight", + "widthMode", + "heightMode" + ], + "methodSignals": [ + "on", + "setRecordChildren" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "661662461fb59800d262dc86", + "sourceDigest": "69c0279a57e43a98b3ac3e7dc38bffbffb3959e3bdc2fa168aaceb33846b2085", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6618db311fb59800d262dc94", + "sourceDigest": "deefed753fba802367ed11407bb604ee13ff60555514710dd7a20bb5dc33ab56", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "661ca9931fb59800d262dc96", + "sourceDigest": "5d504162f703c2e382495468fa3faf8d0e2cdd517485218d89b334763a7b1420", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "661caa0c1fb59800d262dc97", + "sourceDigest": "7120cd6f717481b3d027ecce9a30e86976210f5de176ea2b5e511d4e76ac4788", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "662781ddd4295000ba6e33c0", + "sourceDigest": "bb180d6849f2e6577343cf5c1e5ddc9922347d99decb6c666555e47b009cb49a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6628a675d4295000ba6e33d8", + "sourceDigest": "300d222f2b3f98841ad2f75e413cec71902167ad0e6decb191da287113f50d99", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "662e20c6d4511700f6885626", + "sourceDigest": "0171dffe6553dffee5333cd6177f2f419685dbc4130706c8f9e4618477bbb177", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "migrated", + "priority": null, + "localCase": "pivot-resize-indicator-group", + "verification": "getRowHeight on two indicator rows" + }, + { + "id": "6639d7dab19f5100ced6a692", + "sourceDigest": "4d0121ca5005cf5fa3855d0a14d152f55366f3982649c3f3c86e56c4f8a5a4b5", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [ + "line", + "scatter" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6639d9d4b19f5100ced6a694", + "sourceDigest": "f0a05722b3c1355351054ecfb4a05e49525533c68c67a1838186c5a309d69e98", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "autoFillHeight", + "widthMode", + "heightMode", + "cellType", + "indicatorsAsCol", + "markLine" + ], + "methodSignals": [], + "chartTypes": [ + "scatter" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "663b595f771bb200ac392804", + "sourceDigest": "7a7244ba1a85313ec4759401c868e8002d3523dce0d691d31716631de9607230", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCell", + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "663f393b0b3b8900c63a77f3", + "sourceDigest": "e4cf6b9b9fef364b43cd369660184fe04dd76a52db63be0c7106541eb6da4568", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6646c5abc18c8900b44d9a20", + "sourceDigest": "2f9ec53c4c0a3d96454506580cf608c5e84a610090f72092a32def462992ae4c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "664c61fdc18c8900b44d9aa4", + "sourceDigest": "2526ef8ea49435bc53925e03bd8fd36b1cb712aa0ced012d1511b69a4994b4da", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "664c6278c18c8900b44d9aa6", + "sourceDigest": "a36dce26c2dd1dbf9867b61cb5370d29000ad93f5b655e9ae20f66e949a9191a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "664f2b3ec18c8900b44d9aa9", + "sourceDigest": "f70359461f8c1aa550d410ad156e30e3333917bb86a96d45e22e9f77a98dfebf", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "indicatorsAsCol", + "legends", + "brush" + ], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "665548565a5b1400ab9139e5", + "sourceDigest": "652ad7277607366fafcde85131e856eb74d8626b87630fc034f08c198f518ba4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "665548c95a5b1400ab9139e6", + "sourceDigest": "67e025798777377759d81b06ea1011d0606b92ac67df2418cf8b00937a2ce145", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66554d5a5a5b1400ab9139ec", + "sourceDigest": "ca4c719a9f5062f6e20546e5a2681b601ccd43173ddefa53d88d1793e26084eb", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66557f20c18c8900b44d9ab0", + "sourceDigest": "c2d61c32e6cd9e62d831f5b75457bf34a306a758c17525a787f180dfb4b673b8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6655b8dac18c8900b44d9abb", + "sourceDigest": "8721d427c6451d0006ccdd365987c29b56ab55f7adae031d0bdff89b2ec9dc9e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "select", + "disableSelect" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6655b925c18c8900b44d9abd", + "sourceDigest": "2f3cbc7c0bef9ade283bba0f8f3b32fd56deefab0f85df95b780712bcd515c95", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "select", + "transpose" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6655b9bec18c8900b44d9abf", + "sourceDigest": "89fb0c809dcec12342da6c4f0f9ba9c351ab1fa875b96df5ccbcb19342917ce6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "dragHeaderMode", + "widthMode", + "heightMode", + "select", + "disableSelect", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6657de1e5a5b1400ab913a21", + "sourceDigest": "cd7fcb228ccc0ed9483d4cafdfbe5b5d3ef672557912d0783fc6c1c61c5f0748", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665eb51cfaec2700ad74954a", + "sourceDigest": "af0dde6469423962525a595a17306954da5f001d069969b3f1cdfad25ee20e91", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665eb726faec2700ad74954d", + "sourceDigest": "822f02552ae69ca6ba53a0158722c1240f5482f59ef385de6b30b815e10e9f04", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665eb7fafaec2700ad749551", + "sourceDigest": "e8cb7d829fd0a7affeb7972abb774cc5b7f6204f55c0b0de2eff243c0d08a73c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665eba0ca4737f00b6623d44", + "sourceDigest": "2d6a1000241a832c9fa4736649c8e38cd1d736aed3f2e83507b6a61f5ee760ee", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665ecceafaec2700ad749556", + "sourceDigest": "cc041cf13f1b515995a547b8258d38b57cca6b06d6844fadd4379994f5acaeba", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "headerSelectMode", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "665ecf14faec2700ad749559", + "sourceDigest": "45f88bdfa79ba3c8194cb87c989197c73bba948e55bc2254e9b14eda295f8a8e", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCell", + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "665ed01efaec2700ad74955a", + "sourceDigest": "60556b67e241f85dcf4e18eddbdf0fb839b6e4f9f0bd4ff7fb1785e1b9fbe0fe", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "665ed0acfaec2700ad74955c", + "sourceDigest": "9e6662d2cba98cc0fa5158f6cf37851696b13ef0438ca2e4a8f696af55e0887c", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragOrder", + "widthMode", + "editor", + "rowSeriesNumber" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "665ed0fbfaec2700ad74955d", + "sourceDigest": "fd75dda4b958b7e64941f29258f0188fa06aa7932d4b4cc3f566093c3e2eb5b4", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragOrder", + "widthMode", + "editor", + "rowSeriesNumber", + "transpose" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66611f147ab71300c5d1e5b4", + "sourceDigest": "ad7c0129703dd616d8e57c505e2bd34bd2df693bbf85899f90c57326672ee1da", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6667bae37ab71300c5d1e5fc", + "sourceDigest": "ef8cb0eff6b96fbab7873e161d6c7d16ac34a966bf827b35fd80bc959b9899a2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6667c7097ab71300c5d1e602", + "sourceDigest": "51d13b60c79aee0075a88876edaafeab27ba0e4725f692926f6ecfff70bfafc9", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6667ce8a7ab71300c5d1e605", + "sourceDigest": "7166b744f2d437420385c6d177b36b607513293866b266668f3642e31eb436a2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6667f48f7ab71300c5d1e608", + "sourceDigest": "3454d602013a633cc2496956bb4a2b7be6ea3371c0c1b68efbf339a354987af7", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6667fed97ab71300c5d1e60a", + "sourceDigest": "a48fee51a7509e1a867f91d6b3a9c68e7f6f6ecb6b8f32280de4a13dd9804b2a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66681c3b7ab71300c5d1e613", + "sourceDigest": "67dc7ddd8320db90fcb492d2bb45e39155731bc0cb287444e40166ba6d1aae0f", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "frozenColCount" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6669078b7ab71300c5d1e615", + "sourceDigest": "0bcf6fc9b54a26bd45f993d0d1eee7688984b998c34f4b205ce830e91c47c5a5", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66690a707ab71300c5d1e617", + "sourceDigest": "6739ea903a2c7f9b5d331a47391c7c42293f3d7dca9292384a0ae744ef6c6924", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66690b2f7ab71300c5d1e618", + "sourceDigest": "ab2a567920c87fb4908a83bc6792cc5d5fece32f2f617e1b10a50db477cf0306", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66690c317ab71300c5d1e619", + "sourceDigest": "d835889072006c1cb355b0a0903a35b587eb5196c27f5afb35082213dd21b0a0", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66690cdd7ab71300c5d1e61a", + "sourceDigest": "13d81a9258c93760874b51d575d939c35fb3538774923c9687f059f48e89add1", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "666988d044759500c7c1c65b", + "sourceDigest": "2e7993333489ffe7c4d55201119fbb958627dcbd12d1ac08fdcd228c6c4d379f", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "updateOption" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "666a70ff44759500c7c1c65e", + "sourceDigest": "aad2cf3f27176e0ddb6a28b1b08c7c67f7bffdd7c32bda73d89fdecf6f5cdbda", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "sortRules", + "autoFillWidth", + "heightMode", + "customLayout" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "667281c871989000cfc6dc94", + "sourceDigest": "aa992b9638170a6f6ada3e5af3da1acf89bce368d5d38b5e82a48aba2b8a5fb0", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6672845271989000cfc6dc96", + "sourceDigest": "b9e65d629e3faac44db0b62ad7850c0e9007abf400f1b79efce745811b601817", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6672a8845338cc00af187b66", + "sourceDigest": "f7b18409e781106188341c2a66bdfa742081b1afe4cef3feaf08cff426c8c357", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rightFrozenColCount", + "bottomFrozenRowCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6672be3c5338cc00af187b67", + "sourceDigest": "3f04f391cce82a9e01b853e6a6a20eb3984c0c7d1b151d068a2e0588ecc8b8f5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6674f87d7726c300b462187c", + "sourceDigest": "b6793fb6b06a8751da8cedc719aaa4e86c6b517a4b3c9ba1b29591e334336b71", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "667a8a2af52eec00b51f2748", + "sourceDigest": "b942cc8bd5540510a45dfa6fa2fd3cadee6ab622d3cdf0cabb3d6d920d38094e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "667a8b12f52eec00b51f2749", + "sourceDigest": "cd27b2589df15b56b6630a27cbe4b18add4bc7c9eacdee8ef7b9d03c6f5e849f", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "667b93e2d8703200b4aca329", + "sourceDigest": "dbf434214ced75eb8be21e7242fdc950129c7894fc48338d3186c151ffa2f755", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "667be445d8703200b4aca362", + "sourceDigest": "f6d4271cca0d7c84f6c068b2d9ac9655caeb4bcd9dbcb6d1751ab2385ed44fd0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "sortState", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66800e739e4bad00ca1ae977", + "sourceDigest": "8af508aa050c96280a487a60419b3f24638f23759c0085497c26da90a44eeb22", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "editor", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66973fc327f96000ad549e85", + "sourceDigest": "37f3d806b41fdb2c4bc50525130eff262c7ff84beb1b7c6b24b4df12a6c65e56", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "669740df27f96000ad549e93", + "sourceDigest": "57a6353e7ff520bd398277e4a765ce6c1f969bf868e74d17ac0699a3b2532780", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "669a1adcd62b6300ba4720d4", + "sourceDigest": "ff0f4286ea21c5c1c31215f7d7124b2941953b465741198f18dc1c92d37ba894", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortRules", + "autoFillWidth", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66a09d4bd62b6300ba472129", + "sourceDigest": "c42d840953368bb59c2b899f5a4f5c1c282a16af2b6449d67f5edf07b58d3c22", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66a85ed477da4f00bdc525cb", + "sourceDigest": "81a9613643fb9224d97de5d195e650b264bc3a9991f904cb01c5794d192a147b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66b32f58aeb8a00109f2de06", + "sourceDigest": "30967ca9ece0a3a54b0f1302490afa9da83cf71fdb2ec5b1d11221fb2af7c863", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66b32fca632a0800b3e8a185", + "sourceDigest": "d76082acdf9f201c42ea552249ed34752895ac42576074658c5ee9e0dff2c047", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66b330096d307a00bc86797e", + "sourceDigest": "05b244c15c10caa93450ef8a60e88ce2ac1d7c265ecce0727481cb2150c10c2f", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66b331f2d62b6300ba4721d9", + "sourceDigest": "08aee6d3cf9a10d66d00fdc47db9f41ce93b52125b43a447538710829ccb064a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "transpose", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "common", + "line" + ], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66b58ed6a6fe1500c0461ae9", + "sourceDigest": "304dc76aefc10545d58a7e9f5f11340d892c49887bb0e33bcbe1c32bab6a1a6c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66b5c44f59051b00acb58ea9", + "sourceDigest": "a57dc1ee2d05715ee12140ee8a189be86f7ba89472eb8453466b34d1cda3ed86", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "fillHandle", + "widthMode", + "editor", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "rowSeriesNumber", + "select", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66b5e4aba6fe1500c0461b13", + "sourceDigest": "26a08085c0607cff68e9b55b33c32f5b40ada52cb250496a1e75cfc875852945", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "heightMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66c54e77c3ab4200c6b4fdf5", + "sourceDigest": "eff5f44b541eb21f986d4a510524b0b47064129d727ca7e7160ddb3585fc3692", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66c54ebdc3ab4200c6b4fdf6", + "sourceDigest": "ad8cf6bf6d25d8959d12dd8cca4567d5aa75fd03e7df2beef5df75082f793101", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "sortState", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "baseline_failure", + "priority": "P0", + "reason": "sortState is stored but the expected initial record order is unchanged on the official baseline" + }, + { + "id": "66cd48e95e11d900c8f0e956", + "sourceDigest": "9ce05e54b1edf5f7b3999ade305eb5d5398eaa088ea3804fac9d61b75b048903", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66cd7e4a5e11d900c8f0e967", + "sourceDigest": "aef3ca77adfaf08cc4c410aab76ca64d5f642257ec564e7f5eb6404c0b0eb180", + "family": "pivot-chart", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "autoFillHeight", + "widthMode", + "heightMode", + "cellType", + "indicatorsAsCol", + "markLine" + ], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "66cd835f5e11d900c8f0e96a", + "sourceDigest": "df6b7f31e59b119b057f0e8fbe8607fe32164c76b33b465cd6ac3f00b0c1998b", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66cd83fe5e11d900c8f0e96b", + "sourceDigest": "04c821d67ef23d979c5db9d188d92aa3dbb8dfc32273593bc31eb9f4fdc0e6fa", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortState", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "sort-initial-multiple-state", + "verification": "getCellValue + sortState" + }, + { + "id": "66cecb83b0f41c00c5324c87", + "sourceDigest": "ba7d20f5f7f54ce2f53b1fbe7d4c2be0e5470e3d961cedb9cdb008bdda66bf5c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66cefc08b0f41c00c5324c97", + "sourceDigest": "ea2e710b8c42f9238c3a89471e89e9f227280439ea875d36e26217ed62712128", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66cf13bfb0f41c00c5324c99", + "sourceDigest": "b0bb579766d411010a330c48b11d52b16907c9b9d6d867228c8fb79bdd74dd2e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66cf227db0f41c00c5324c9b", + "sourceDigest": "0ade7b5bfbf4eb8b98cad78949dd9e09fd63a804b3bb8e5f9f001adf08b206e6", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d17bd8b0f41c00c5324ca4", + "sourceDigest": "d88ee0ad2a2476d0a8f62be297e08d2dc69533921846b12f52f9365b95c742b6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d6c7f1178e6f00f99be0d4", + "sourceDigest": "fbd65f0b2a688e0b0e116bd10c3ff900ff65bca2ab6fe5176dde465b7e81a024", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 8, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d6d0b3f53b2e00f749f331", + "sourceDigest": "e86b5b57eb43b40591bdbdc93b9ef5bfff2315fa808c713075610764baa47092", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d81a31a892910101d39af3", + "sourceDigest": "3c2497cd0f5f249b2f331a8368b5d7acaafb51c4dff6c28d9cee009d18016d63", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d8266efd533a01263a0585", + "sourceDigest": "38eb2004fab799d96594534df8a98b2df6644c6525d6a5e8e6feb01536f30c41", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortRules", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d828b1fd533a01263a0588", + "sourceDigest": "859f65bf314654ed48fea1d4292ef904c0eab651fd2c0d80bf50aea35d102477", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d84b0d178e6f00f99be0eb", + "sourceDigest": "a5360b1173848ae753a2e540a07c29aa8837824955fdacae1cea82aebe98c739", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d84c44fd533a01263a058e", + "sourceDigest": "22a7f8673ba0057da1833dbce7a0da29f05c08479ccd9fd359e54c21be0db9b2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "sortRules", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d91d5afd533a01263a059a", + "sourceDigest": "add7a70da4dcd7a804d7ae0bbcad3ec439e17e2a582e1770d8482fcc40166310", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d95d69fd533a01263a05bf", + "sourceDigest": "49f965c9a00cb92d395008b1e4e116f2a7da93c2c39fdf80ab09d816c0a7e2d3", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66d971e60297dc00f7968894", + "sourceDigest": "131f09da78464cc63ebf719b9b05dd8971e71fe03c84a8a13c39c643cd582564", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d97ffe488bb800eba8cdb7", + "sourceDigest": "45ccc388e4b99f050f06d4091838115d94df6192dc0e364638f1a1c6d1ef40bd", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d99cd23c31b300f9c76235", + "sourceDigest": "4df7caadf162c6ae207b6e49a493f905eef93d1e82b4be86af1afbd7dcd924b2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "heightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d99d210eae0a00f267b3df", + "sourceDigest": "ca435f9d4e766c9b3fe4301a765d3e0f4ad4d44df33c86736ece2ea986236496", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "heightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d99d5872bb3f00f07a6e4c", + "sourceDigest": "48d516c574414a8cec244ecf410abde3a9874b53693c083dbf0663354b59361a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "heightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66d99d950846a700faef5dd9", + "sourceDigest": "9bc42dc9e1d6bc859e9b6cf5bb38db8b528aa02e099271295326bdf4335b5593", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "heightMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66da73450846a700faef5de5", + "sourceDigest": "df516d2fb537afc2aee686d1f06c6567396f622536d86d9dad2baf1c858fccf5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "pivotSortState", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66dad08152553d00fb0c9205", + "sourceDigest": "8e03b99936eb9092e7c173879d65a7ec405f5496c914e75a3fe5a10919d5e295", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66de62650846a700faef5e25", + "sourceDigest": "babcb785287df1287683f1c3f8e593dbc8521e3fe0b1a7cc73e61c078bac8bf4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66de93b00846a700faef5e3d", + "sourceDigest": "06b5fb21841480518ab159eb2ff3a8976e384e57e2914021c2eff126972083d7", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66deb2e30846a700faef5e57", + "sourceDigest": "798689b647bf4a8988d75e8d6187be442eea4583761b92b372fe7a344da8f248", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "widthMode", + "cellType" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66e42c6d0eae0a00f267b445", + "sourceDigest": "233aacf312ad66530d2fd511609db79fd599433f0056e659f5af6c76a60beec6", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66e42d350eae0a00f267b446", + "sourceDigest": "4cdeaa2a603c8517842b20add08d6ef1483a4ddfe363f2e28d64bd7bbf4468cc", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66e838f0e905a400f73269ec", + "sourceDigest": "2bbd9d4b856d0ed3c991b9bb6fc71d03f1c8db16aa52f0aebba922126ff82236", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66eaba5072bb3f00f07a6e68", + "sourceDigest": "bdae2e52f90cdec6433691357107200c5b70a1b692c46983e1ef8dda46fb718f", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66eb97f672bb3f00f07a6e7f", + "sourceDigest": "92bd3252c2575a081518b688a3b38eb2c62fe2c72e0a5c1abbf881e6b7dcfcf3", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66ed3e6e81adc800ee4b03a4", + "sourceDigest": "eb4b265ea256d289262893ae72478ecc0d0942a869e65e4b68258facf55d6a05", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecord", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66ed3ed53b27d700edcbbb95", + "sourceDigest": "44594d790a1c15291b45ce54dbc2c9b05b4702be23b45dfb80b457dab4dba606", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "addRecords", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66ed3f55488bb800eba8cddf", + "sourceDigest": "4119de6badfd2353e18736340ee344aa5c5c8b4cbfd3168f0088ac3a0878a168", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords", + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "66f504ee885776011c598a61", + "sourceDigest": "e6c666de3b35e911bed2e1c1260384d98496ae13f867bf815cb74322c304a989", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "66f689cd33c1e900bc71e36a", + "sourceDigest": "b1234b03904eb071f46c5b1f87fd47ce2fa82fa95a71423baef8f69c3bd3d953", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6704cd0d22f17300a767a2be", + "sourceDigest": "02d81ea369c33f60aa52b75aa2fc24e40521c5d067ba3b20ab0dc61a2dbc03f0", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "autoFillHeight", + "widthMode", + "customMergeCell", + "customLayout", + "rightFrozenColCount", + "bottomFrozenRowCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6705f78a22f17300a767a2cd", + "sourceDigest": "6a077d6da6e5c4ce98ec3982868b2232689735a317d7c69527d0e3f70263688a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67066b9022f17300a767a2d8", + "sourceDigest": "2d8173a8d767cc4dd446374083e7882079c7f98424e046877b062506601d21db", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6708ede6241d7c00a693a15a", + "sourceDigest": "6726f41dc7f1e802b3af3a615958a93cb09f3296941540e89dd500ebdf642024", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6708f11e241d7c00a693a15b", + "sourceDigest": "7db916119185f4177f4a2b9887853b05aef5664fff5123588dcdf34cb09fd1b1", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6709e882a2b8c200b0bd6544", + "sourceDigest": "fdca62e0ebb7685a21d8b920a678c692f52f54e1947ac115b0d33434fd01ddc5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "671624efbb067d00b20cdc0a", + "sourceDigest": "7796d71cc107db22924fcabc066c0967171faa7b2e71912234cd357ee69951f1", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragOrder", + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67177444e4bb4400b299cab5", + "sourceDigest": "689bb68b4acfdc4d65dc6fae62dfeefd2fe4b08c7f52e0dff958efc073164595", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6718c4b6d7996f00b2b7c4d3", + "sourceDigest": "33f5327b48bf67f738ef47ae7ebf24522421b75df5da03cff205684b7f74f744", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "customLayout", + "frozenColCount", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67209e48e4bb4400b299cb47", + "sourceDigest": "e14ebef35aa7c204b28780e3cdc0906ae3a5e94299e9eb91cd4632a3cc1b9e87", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6721cafbe4bb4400b299cb4b", + "sourceDigest": "ceee9b498a7ebb658a34a2231a6aa74a73aa5f993fcf96d5e9c1cd1dec615aec", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "widthMode", + "cellType", + "frozenColCount", + "highlightMode", + "pagination" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67220c9ee4bb4400b299cb5c", + "sourceDigest": "d33d7daf23bb0ad269da5bbe97914ae2312c32da11848493f7802d6ec9cb05b3", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67247e1ddc57cb00bc3be948", + "sourceDigest": "7826030651d4d33cd8a296586b058a994a2e7c7e6c163f16b8df39a29daaac05", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "67247e9ce4bb4400b299cb86", + "sourceDigest": "c07c7d2ffa36c938fe79818024c52b91951dfc8d59aa14ce4428ba416628b117", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "editor" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "67249192e4bb4400b299cb8d", + "sourceDigest": "7a8672a916c10c608479dde5c85bd065656a78cc2b30ce80b7d8ac8e76658059", + "family": "pivot-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "autoFillWidth", + "cellType", + "editor" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "6729c737e4bb4400b299cbb0", + "sourceDigest": "67a7578ae72d3534be27a9b94dc69b9b83a336512c3dcadf72952cfdfa77696d", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "cellType" + ], + "methodSignals": [], + "chartTypes": [ + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6729c7b7e4bb4400b299cbb1", + "sourceDigest": "419b8f86839c46238de5a838f0f4eaeb9d13f112943e7e577ee5d36f431a2689", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "cellType" + ], + "methodSignals": [], + "chartTypes": [ + "common", + "line" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "672b5b0b71189400b2ec8d56", + "sourceDigest": "b84590b3d7ebe04bfaf5e21e69fe2290bfda18fa1d6d46dcf3c54b9da2fb4427", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "672c9d90e4bb4400b299cbd2", + "sourceDigest": "8cbf8568efe00d07963852e66c53061917f346c6f044bb7c4a2e731c9eae65eb", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 3, + "optionSignals": [ + "select", + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6731b2f3013a5500b2fe994d", + "sourceDigest": "e99b20d2e3a15bfdd99632ccdc76f06b295dde8b30de747ec68a37888fb4d6ca", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6731eb3f013a5500b2fe9961", + "sourceDigest": "af5dca9daa757f09e883b04b28db686a5b8b85ac0fe248e4e6b1f7a1fa869365", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "select", + "disableSelect", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6732f2e1013a5500b2fe9967", + "sourceDigest": "7c61ade475fbb96419f76f9a0e32673d150718173f1a94f9483627bbaf05e951", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "highlightMode" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6733203d013a5500b2fe997b", + "sourceDigest": "2dd417f03348da71f194bb65f2cae0be170f1da3a5ed1ebe1fe2379e003462f3", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 5, + "optionSignals": [ + "cellType", + "rightFrozenColCount", + "bottomFrozenRowCount", + "select", + "disableSelect", + "markLine" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67332c11013a5500b2fe9983", + "sourceDigest": "c6e5dbb8da7afe142e6267f8da33d4fca9021b05844ec5c5645e7c9a5d19b5a2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortState", + "autoFillHeight", + "widthMode", + "heightMode" + ], + "methodSignals": [ + "on", + "setRecordChildren" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6735c61c013a5500b2fe99bc", + "sourceDigest": "2d4023ff16f6440360a2bbda4dd910e0d1c28cbccd86df12e664b519fbaabdc7", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "cellType", + "select", + "indicatorsAsCol", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "673728e9013a5500b2fe99ca", + "sourceDigest": "696341ec2156c2dafc5d5dc5dca44011ece677dccc31156798c1124c659f2eac", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "673c5c17013a5500b2fe99e0", + "sourceDigest": "b7dc1f914eb4a4c84eb15f0f523aaa96ea5fadf167a5d8097fc4687b2640b200", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "673c5cad013a5500b2fe99e1", + "sourceDigest": "c533768e7169baa59d8915e99cc81568d59fc23e2cd5308a00447540d90368b4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-custom-compute-row-height", + "verification": "getRowHeight" + }, + { + "id": "673ece4c3a9fee00b29bd92f", + "sourceDigest": "1bdd55b5ca492f39737f59c7664b076feaad3ff2739d70cb9862547f952e963c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [ + "selectCell" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "673ee7133a9fee00b29bd934", + "sourceDigest": "c35ac001bc52610d63bcfa411ceb33e3223a0b6a9b688e7434f11acac5bff7d1", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6746dcfa71189400b2ec8dc2", + "sourceDigest": "a62292e0b44356bccd38c6d6e16f4fb95a28effead24160dd0a9e3abd734f405", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "cellType", + "frozenColCount", + "transpose", + "legends" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "scatter" + ], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6747e6693753cc00b3d7d303", + "sourceDigest": "72939438e5586d4aac27782b54d6daf5ae01c574dbd6de5c7fd0d3e22bf03065", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "widthMode", + "select", + "highlightMode" + ], + "methodSignals": [ + "selectCell", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67484cda71189400b2ec8dcd", + "sourceDigest": "5cc48b6ffd4dddc076795c6b7c3d48bf8f68c01cafe56b02aa8c35e7c3c6c2c9", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "widthMode", + "cellType", + "frozenColCount", + "highlightMode", + "pagination" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67497d4271189400b2ec8e00", + "sourceDigest": "28320c2b5f56462dd118e01d4f0dac7dfa199342bc86f0f3fd52af58d162985e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortState", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "675f9c36bb067d00b20cdcc1", + "sourceDigest": "d2c4bdf1e3bbe1a77861b7035ae0f71fe36a8f55577bf189add6baa5a050cfb8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6769255d86624500b106bd3b", + "sourceDigest": "ce5a4c08640aaaded15e52a4067ab6f970436f4a4526981e4c00488c17e6f3ac", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "getCellValue" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676a70de0982bf00b14e2316", + "sourceDigest": "5cb93df90be249057b812f05e19220af249c47404535e748fb38b8a2a84be350", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676bb773df600200b24f54db", + "sourceDigest": "d544cdda39aa049ebe425eb41541fb3bd5bf7d1d1ecf245ade05b3b22d360465", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "676bb7bad2dacd00b3443e2c", + "sourceDigest": "d14c17346c3cdb0a820292c52dd9884913bf988273146ee1935046284492769a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676bbdfed350f600b2968c68", + "sourceDigest": "ea200739bd7041d47b9327c2112af30346034fcb6d6c8ae3138654268858819d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "heightMode", + "disableSelect" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676bc00e8e768100b114c2e7", + "sourceDigest": "07405940f2e54b2a034d51140476fe289f789a17a80b2bd2a6fc19b038fc61dc", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676bcd663e30ec00b2fffc17", + "sourceDigest": "25d7c0f9237860f27c467d94b351dab31343db0cbda4af77297f90a6a44d5790", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676bcdc554366a00b133b6be", + "sourceDigest": "874f7645229c794464e7b0e403108967a145d2e149bdf3d247f071f4ef017e8e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676e5dafb6ef7d00b00e8f37", + "sourceDigest": "1eb351a00e3674fe4d17b1274c2924b0fa3c22dd16bcdc0632b0fff4e80e1db5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rightFrozenColCount", + "bottomFrozenRowCount", + "highlightMode", + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676e65cfaf3eab00b23490e2", + "sourceDigest": "87d32e1505a299841f9f91c3bf11d42ed813fe5d287fca7f482c3bb499155da8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addRecord" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "676e6bc698804d00b1d620de", + "sourceDigest": "8db6496c8f90ee565ea139b0cd1c863efd9fb15d5f9ee41e43e3ce87fea4861c", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "dragHeaderMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "676e6d3820512600b3dfc3d0", + "sourceDigest": "751fe330b337d60e4ec9fa8faf3822ff38be6d455cbc6c2cc4591339e9319f0b", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "dragHeaderMode", + "frozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6777a053863ad000b1fc4055", + "sourceDigest": "b668048f5693ddad53d8e238a4e3d5b8e4e364fb0477c214bbc6f8bc5db0f435", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "showSort", + "sortState", + "widthMode" + ], + "methodSignals": [ + "on", + "setRecords", + "sort", + "updateRecords", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "677b78bf8e768100b114c37d", + "sourceDigest": "46f096c63bf149fd382b09c33cd46f66f3c53222d9fb93359eca0c81f48d6d3d", + "family": "pivot-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "677bb879df600200b24f5564", + "sourceDigest": "af7ccb621a4e8f5a6b6256af5bae9f2d73bef3e0da7833f347bfda53aa03aa2c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "678620838e768100b114c398", + "sourceDigest": "6e9479cf70e173af05d799ae91744509c712195a2fc245bfe13ffc5efd76acf4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-canvas-size-options", + "verification": "canvasWidth + canvasHeight" + }, + { + "id": "6786222198804d00b1d62177", + "sourceDigest": "7afa66b5c1da57957e610af9b7c4e47676ea230733d44146d11d9938f515268a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-canvas-size-options", + "verification": "canvasWidth + canvasHeight" + }, + { + "id": "67862349af3eab00b234917d", + "sourceDigest": "e2496f09ca146898447699d774d9dfb92aceaef0cbe3791932968aca98abe25d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-canvas-size-options", + "verification": "canvasWidth + canvasHeight" + }, + { + "id": "678624597020de00b01c0b49", + "sourceDigest": "7ef2c10d93c0816278f010f53aa40c50047c5fec837fc8f18bf69ae634df2ce2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords", + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "layout-canvas-size-options", + "verification": "canvasWidth + canvasHeight" + }, + { + "id": "6787a19f01916b00baea8448", + "sourceDigest": "39840f23a08df931d48c6a8834cb2cc63fd10a50c57c586ab8a4dd5073c92386", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "addRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6787a5e7d350f600b2968cfa", + "sourceDigest": "8eec0c062ec24abe2c55494d1df2521ebf22b49e65bb6bd588cdef98fb3c40af", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "deleteRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6787a715af3eab00b2349184", + "sourceDigest": "9d14883ead7828a3eebf16d175241c6ddd98f90cfb93db4a90f9c00663f332c6", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6787aea5863ad000b1fc4082", + "sourceDigest": "7280a6096c5d499bca7f0997a184332ad533b78535d87b14b64b81af7cd95e67", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragOrder", + "widthMode", + "cellType", + "rowSeriesNumber", + "groupBy" + ], + "methodSignals": [ + "updateRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "679b5bae03fdbc00b04b20db", + "sourceDigest": "4d972fa2369f1ec5dfdda3ac67ed45ff943f1b8b4a115e66f369ccf3b4377d6d", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "679b5d395091f000b1aa56cd", + "sourceDigest": "633201cc78d21d530234ce8540df616eb925602661009440b0e4b89b88b78ddc", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "columnHierarchyType", + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67a4a0327c7ae300b1a48b54", + "sourceDigest": "f961c86309ed18ad6d6ec1f89ddf56480b10bc7b4d3911d97212b3a09c5b9b8f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67ac19437745ab00b1614f0a", + "sourceDigest": "4370fd7bac2252b760fdc9b728e74240730e730664f67f16bf2feba9beff50de", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67ad93987745ab00b1614f0c", + "sourceDigest": "e6710e08ec0ca684adb37cbfe8d06b1c5a4849b3e46a2566619baa6724628200", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67ad96ba773c4000bdf99d61", + "sourceDigest": "fe88c646c3c7a6934281d41e7083c6af0e98fb801c15d445148d9b4b9731749f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "transpose" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67b47421c1cefe00bc77fb71", + "sourceDigest": "ecc4c0ca46805945ef36e823a3cab29dfcfcfaf5987a548a9d3fe82f092d1ef9", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "67c563535f787500b2874704", + "sourceDigest": "681f80a1d58e34b2367cc4ac8ae6368819c58377bc152b71e483c7cf36d7178a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "sortRules", + "sortByIndicator", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67ca9c6cae681000a7b22eaf", + "sourceDigest": "b1d8d66e7b0685468300a13be39d95311d9edb84f6e99da0b9f5feb235d4c09d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "sortState", + "dragHeaderMode", + "dragOrder", + "widthMode", + "rowSeriesNumber" + ], + "methodSignals": [ + "on", + "setRecordChildren" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67cea3ea06d94f00a8e3a6a2", + "sourceDigest": "dc54fafa4246e63971b1fbfaa10c0102952aedb746f2317ca6863cbef00ff885", + "family": "list-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "67cea5077e106d00a74f27dc", + "sourceDigest": "b17dbfee6e3d20a9e507cf418897a375016d188fbeb640f7768d3ee5a0520b9a", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "showSort", + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [ + "on", + "updatePivotSortState" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67d00aa7dc8abb00a7c081b9", + "sourceDigest": "89ca32bdbfd5a085977fad6f06c94909a59f06d4e47b2b331fc7f5e381aa5d96", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "rowExpandLevel", + "showSort", + "widthMode", + "heightMode", + "cellType", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67d7c346b8637b00a7a32251", + "sourceDigest": "503b32423243a84dfe8949762e6037e59ecd238fe5d39f2a8e2d9d2b0eae8d5e", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67ea804057046200a70ed549", + "sourceDigest": "29e790154d0222d74d02670211f0afb9be7900fe57809d44f432a91a59181bd8", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "pie" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "67eb9c2ab8637b00a7a32277", + "sourceDigest": "77f22af381369b79d0fcc6e335e5b9129442d231947f38f89b7bd14aab37654c", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67eb9c5528b4c200a9da9963", + "sourceDigest": "c1612b17c50029cded0a0330e6b6ada3d70db59b8580312bbb8dc6170d30857e", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67eba04b7e106d00a74f281d", + "sourceDigest": "fa1ae1b92622425495f9758f7d7c2a99b9406262e7e050dcc4622b5efee4f341", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "67eba18063ae2300a3122147", + "sourceDigest": "8b602cf038b7b45578f11568a6724d5fdc1ef0f06ef392bac8a394e08628e1e8", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "pivot-corner-remaining-variants", + "verification": "rowCount + colCount + canvas.width" + }, + { + "id": "67eba1e52ef4e200a7775a9c", + "sourceDigest": "0644670fe7aad27dbf78acfdcb2ca683bf36e31dc69265028d97bd92214bc6e5", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "pivot-corner-remaining-variants", + "verification": "rowCount + colCount + canvas.width" + }, + { + "id": "67ebb661b17ad700a78185fd", + "sourceDigest": "1aece69bcccc31edba88421c2551a69d166298ee5114742ae5b4cdfcf4e71d1b", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "dragHeaderMode", + "autoFillHeight", + "widthMode", + "customMergeCell", + "customLayout", + "rightFrozenColCount", + "bottomFrozenRowCount", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67ecf4e1d4307700b694535e", + "sourceDigest": "b09df7c5083e64d98fe5d3ab2785bfa3309bd310f0e8e1110ad4dd925376414d", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "pivot-corner-remaining-variants", + "verification": "rowCount + colCount + canvas.width" + }, + { + "id": "67ee3c68f6d6fd00a872e89d", + "sourceDigest": "65ce5b971da228a3c99a5ad98284dd2bf985247afce6493198e19feee206d16c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67ee42fdd3963500b3ec8266", + "sourceDigest": "5132c7e0716c1187b2dafe10d02928de61cdd737ea7a05d656d845323739d551", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber", + "select", + "headerSelectMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "67f37130dc8abb00a7c08200", + "sourceDigest": "942a038c58e3eff342c2a94a7a12a306669fc650c4c15dad21c20d9a57549a1a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "widthMode", + "heightMode", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "680616a22b0c7600a7633ca6", + "sourceDigest": "3b1ba5e8cbe3140bbcb1b6d83fdacc2c4f09000d1dbd63b248b7fed9f9a32ac5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "681c2a5ab01ec400a9952511", + "sourceDigest": "f3b268d14ffa68a31ff33810bc31ca79f670e17500f618d17c8604821a6aff7d", + "family": "gantt", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "cellType", + "frozenColCount", + "moveable", + "markLine" + ], + "methodSignals": [ + "release" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "681c859484849700a73864dc", + "sourceDigest": "dbb213f09b82b29be11fbbc865022633a85b4118bfdcdcd409645d4f123b2a50", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "heightMode", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6825cf222af66800a8883eec", + "sourceDigest": "05bf2e58f47749719b09ffadac6d17d20a82559578f75dcf3fc02d96a6427216", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 4, + "optionSignals": [ + "sortState", + "autoFillHeight", + "widthMode", + "heightMode", + "cellType", + "select" + ], + "methodSignals": [ + "on", + "setRecordChildren" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "682af6dd9736b600a9c14d2d", + "sourceDigest": "e1e371b54b07bac879ac21ecfa4d0713236286ab96ac728a00c21f3a45af5b37", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 3, + "optionSignals": [ + "dragOrder", + "widthMode", + "cellType", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "68355f7a85125600a8d8d2f5", + "sourceDigest": "619abf86480a613c3c91a890da0400547c00f2cc48eab47a0b13d344e3ef34e0", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6835816bea3ac100a6de076c", + "sourceDigest": "4c5e0cb797e7cd7a24e6316d9c1db43c09e008adf85d2066eebc990415f210cd", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragOrder", + "widthMode", + "cellType", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68381438ff077e00b3999c17", + "sourceDigest": "42708e471267be824187d77ac2bd7066b17860939340f86663026f7e5486522a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [ + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "683ea8ae83f5b200a644bb88", + "sourceDigest": "88235b1705306a387332127076b52e3845915a788a1a3b0864dab2967a60a15f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "sortState", + "dragHeaderMode", + "heightMode", + "frozenColCount", + "bottomFrozenRowCount", + "groupBy" + ], + "methodSignals": [ + "updateFilterRules" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "683eae5f95606700b42ea9f8", + "sourceDigest": "5864704197761d197d1f268b48fccd2922c3908f8581e12e0bc467ee7d8291a6", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "684bf16d0ff98d00a8ab8422", + "sourceDigest": "c955621bc34848ce1bd05dd26ec34720a0ed3c8e0fa49f44944ba1f1418e41bc", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "on", + "updateColumns" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68551e92ec174500a64d7506", + "sourceDigest": "e31c39a6a12eda8978ae8efd5bb69b85d8bcc864c77fcf891c7f896dadcf00a5", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "685a21522d188e00a8fe63f5", + "sourceDigest": "8b20f57934ca821fd80e276ed1c29342233f733d5d7cd88972bbaed27d935296", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode" + ], + "methodSignals": [ + "updateColumns" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "685a47007e0fca00a71f22fe", + "sourceDigest": "adc2cc8872cac32b76dc7650d340962c9890bc83287c46f60c9dcbc6a069d783", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "groupBy" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6863aa8484406200a7ab3d49", + "sourceDigest": "de5fce5d9aee54264ac45f92a5b8debc48e9b8b327cefa5659f7ca30baa35444", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "heightMode", + "frozenColCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "688752cafce3b700a79389e0", + "sourceDigest": "4cf59735a119faed16655c086dff6558f0fd7a9e21d8b2dfbaa0c303f78aa106", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "sortState", + "dragOrder", + "autoFillHeight", + "widthMode", + "heightMode", + "cellType", + "rowSeriesNumber", + "select" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6890669a8af47900b375bcd0", + "sourceDigest": "460a84110c70d912b2e5c6de165716e1efcd2fae7a4c71253d95c5b5ad2eab4f", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "689af7926dc79400a6bdb7d9", + "sourceDigest": "acbc07ab37d9617efbc52c78bace8567916a62a4d28ea5d3d734e3aba2ddf49a", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "689af908bcd29200a74f09b6", + "sourceDigest": "411160fc22ba4593c006c5c909048c8a078fc4ad5b3ba88f1e6ed5566e91a9aa", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "frozenColCount", + "highlightMode" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "68a2e109fcb96500a7134dd7", + "sourceDigest": "bd1d2b2b6600859ddbb41157d1f3ce086d65c5597dd10616c6a6291709340ccc", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "frozenColCount" + ], + "methodSignals": [ + "setRecords", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68b012cb8af47900b375bce6", + "sourceDigest": "5fb5b408c0dc1ae463696f306c6793449b58a55c4ec4d316e4e2ff94cb982bf7", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "68c141a407d0a000a8414c22", + "sourceDigest": "c3ee2d5be2457ac537945cdd1a6cffd8ae696d68f67dac7e2d77bc1e242a0160", + "family": "list-table", + "sourceBucket": "needs_resource_review", + "recordedInteractions": 1, + "optionSignals": [ + "showSort", + "fillHandle", + "widthMode", + "editor", + "frozenColCount", + "rowSeriesNumber", + "select" + ], + "methodSignals": [ + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_resource", + "priority": "P2", + "reason": "replace the external resource with a deterministic local asset before claiming coverage" + }, + { + "id": "68c28041711d9200a827cd52", + "sourceDigest": "d35fe10724bf45a3a8cb1e1facd70fd2884adcb64cf77e2e63db44ea0f7148f1", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "68cb7c2e022f2e00a798882c", + "sourceDigest": "7672de6eea9cecd929a59f94159fd748f30f8913ffd5ea275d267096c9c2a00b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "heightMode", + "cellType", + "indicatorsAsCol", + "legends" + ], + "methodSignals": [ + "on", + "updateFilterRules" + ], + "chartTypes": [ + "heatmap" + ], + "actionKinds": [ + "drag" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "68d5fd759b3d3c00aca4fa1d", + "sourceDigest": "bd3cfbedbd0cb5c4b2f0d2a3df6beca570b1512758aafcb1ecb8c291221398ff", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "dragOrder", + "widthMode", + "rowSeriesNumber", + "highlightMode", + "pagination" + ], + "methodSignals": [ + "selectCells", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "68da2815ea187f00a7eeecab", + "sourceDigest": "d9889e9006e1eb8e579e745b75926127352d2580adefa089b957f6006b69d735", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "dragOrder", + "rowSeriesNumber" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" + }, + { + "id": "68da2cb2479d9000abdefad4", + "sourceDigest": "81759f9d92ef9c3a9e103aa01f3fdf546e5dd8face87b44a259d38521f98e674", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68da631f98ac3600a8a21cb0", + "sourceDigest": "e67233b24f64b0274b3444b3968208bee35c6b48dcd7a045a85a461ea48079b2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "groupBy" + ], + "methodSignals": [ + "release" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "68ff1d7f07d0a000a8414c50", + "sourceDigest": "39337694788549c9c480a2c3b6caed6c4f68b088dcf61373ca563b481ab9d46d", + "family": "sheet", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addColumns", + "changeCellValue", + "getCellValue", + "release", + "setCellContent" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68ff1e7c479d9000abdefaf9", + "sourceDigest": "8ea3fef006f4c9dd005502cf38aa0b817329a05e06c9ec1611a68a487737114a", + "family": "sheet", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addColumns", + "changeCellValue", + "getCellValue", + "release", + "setCellContent" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "68ff243743ec0700a96ec5b8", + "sourceDigest": "1b7bc8dffdeb5be015418c19c741081aef0ecea7be03e0b4900a4e22d54ef70f", + "family": "sheet", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addRecords", + "changeCellValue", + "getCellValue", + "release", + "setCellContent" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6915877abea5bb00a82e33e3", + "sourceDigest": "9fdd2b1b8caa40a8acebaea53d02ff3c0f6e8265b3f15c52b5c0d20f9df3513b", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6916e90973443000b25cf383", + "sourceDigest": "143df592c6628a05c718298f122469b48c05f0b4401c6e600539cf9ab7dd24a4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [ + "cellType", + "indicatorsAsCol", + "chartDimensionLinkage" + ], + "methodSignals": [], + "chartTypes": [ + "line", + "scatter" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691ae62a9fa5bc00a804fd0c", + "sourceDigest": "226ea2c65bff1100013db7661b0a6eeb42bfb7540767a1385c4ba16ccb676bf4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "area", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691bdb5fd51cdf005f9518b9", + "sourceDigest": "115574a2d96e3b6668270abbc789074492cc895c00c492f69b0125544fca963f", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "area", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691bdc626d5962005ddf928f", + "sourceDigest": "b4d0d3669d5c6f3efb5943e2abcb2e048b0e4f6dd22f5efc29619209c5dd86b4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691be2fdac45d5005c73eeb5", + "sourceDigest": "8a348277cbe839b8a2c82de228daacaaf3a60d34859071d1ebe1ed7982db5cdc", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691be5806d5962005ddf9290", + "sourceDigest": "5d9e39030c6f922b5b0401d535393d38c00327bd4439ea987561914d8a669619", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 3, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691be61103bd9b005bd0d506", + "sourceDigest": "14c8fc93d9a74fcb6031138d29aa69cc64a3911b435d049533a01b8ae01fc63e", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 4, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691be68b99e1ad005c651788", + "sourceDigest": "a530a11d741c86712bf8a59ce36780bd46bef7f1a4be93b6cea80b3e076330fb", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line", + "scatter" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691be7ba6d5962005ddf9291", + "sourceDigest": "976ed725a40be5c859a4ce20e409593ed5f1e86a45c476b5d9031a0ed3c675ec", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "pie" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "691fe2f6cfcfbb005cb0452c", + "sourceDigest": "045d8f4e35cfafeadf14db72eaee1a4bd9184dbfb11d5eb29815231ab4d857aa", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "boxplot" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "691fe393215128005c991a94", + "sourceDigest": "9be2efb5402220e3bbca0825675eeed09f704e1a0626c7ea099b5643636545f4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 2, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "histogram", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "691fe3e96d5962005ddf929d", + "sourceDigest": "b5ca442a00ba80f661048a1d2bac68ccccd18f3af7920839086a5723c40df24a", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line", + "scatter" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "692914e31b77b1006634e812", + "sourceDigest": "edca627d148c4c86aca8dd61e7018ab4972eba023781edee5001cbdaff2ef6b1", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "autoFillWidth", + "autoFillHeight", + "widthMode", + "heightMode", + "cellType", + "select", + "headerSelectMode", + "highlightMode", + "indicatorsAsCol", + "legends", + "chartDimensionLinkage" + ], + "methodSignals": [], + "chartTypes": [ + "line", + "scatter" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69292cda9995e4005d1533c2", + "sourceDigest": "b8cc6ba3a8b838a29feec894ded86c7511328a030c20760babe855247600459d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "editor" + ], + "methodSignals": [ + "selectCells" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "692d599f94f4f800664fe7a5", + "sourceDigest": "c3b02070addb4dfade08f2f83bc2e699eb6005bffeeb647ec71badafd37591d2", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6931392fc2ba7a00667c9f7a", + "sourceDigest": "f9d1d94c0e098545f2e6ea8ffc083dc3968687cb6f5840b400fb129ba23775b1", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "boxplot" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69368363b0351700666bd27d", + "sourceDigest": "2668426d48bc67c014411731aae4efe356fcd0110793060f06b2395cb6b4b471", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "histogram" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "693b9f82065e8a005c9c62a3", + "sourceDigest": "3781abb3ae8df19115cfe41fe5eda5c7a67fa9059a770b4abbc53b2685d503fd", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "rowHierarchyType", + "rowExpandLevel", + "widthMode", + "heightMode", + "cellType", + "frozenColCount", + "rowSeriesNumber", + "select" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6942732a862ee80066b9cc4b", + "sourceDigest": "bc717ccdadcd0b39df9b0f9b6636b80fdaadc2af1657c9d946eacb522100a734", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [ + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6944fa18d64f80005dcf0f6e", + "sourceDigest": "4d8076bf40d550561a2e29cf97871a17ba5e9fbf61ee075296377999b7ebc382", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6944fa783a0a25005c12ceff", + "sourceDigest": "d37ac176a22a3808b4e4a105b8da1ede72e7a157b020fb7da7527df9ff3f2cca", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar", + "common", + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6944faf3b0351700666bd297", + "sourceDigest": "9d9bab51423e04f8f65d01e70f5c21cff8d7f19ff2c1bf37549bfce28df4dfa5", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "cellType", + "indicatorsAsCol" + ], + "methodSignals": [], + "chartTypes": [ + "area", + "bar", + "common", + "line", + "pie" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6948e4bce92471006708ec4b", + "sourceDigest": "b16fb748158520a0cc559dbbe90a42a1674fdbaf2ba01392a9347b81519167dd", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69532d5356fc63005df9d064", + "sourceDigest": "408b8a3dc46dbca17d71c462055d29f60e8c8c2393e119213248a24295aa2a3b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 4, + "optionSignals": [ + "indicatorsAsCol", + "brush" + ], + "methodSignals": [], + "chartTypes": [ + "bar", + "common" + ], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69533c23ba859d005d8eec1f", + "sourceDigest": "b3e726a5f68bba94ebb24ea80e497d9b95a6d12bb9754cde8f43404ad6b69fe0", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "chartDimensionLinkage" + ], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "695347df862ee80066b9cc60", + "sourceDigest": "acfc529d61aeb576f686226f027f80b6d58335df761c2896840595c53722b1e4", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "rose" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6954de338ff7e3005dfc6526", + "sourceDigest": "88c05d2397359a269736ada4aaa41bb422472ba214dac7ac62bff8348dcf0933", + "family": "pivot-chart", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "chartDimensionLinkage", + "selectedStateFilter" + ], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "696739d9b71f44005d359b67", + "sourceDigest": "80bc7f27621d9f7db36f63210a002e563c1a39f8d09ab5dbde19aeda38781ce7", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "click", + "drag", + "move" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6968ba3844e1cd005ed63372", + "sourceDigest": "2f3e1cfc0b47280986b78cbd10165305c9f55a046c335c21637174a68a96a76b", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6969eb738ff7e3005dfc653a", + "sourceDigest": "821b384217c80cb190228ef3558b9b3796fc0021df92a4eec5ac2014a59d7345", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "deleteRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6969ecde09038a005df130aa", + "sourceDigest": "0467ac1b95d5008579cea6cdefdbde1c96ffeb278977eaa4f7abb8af8696eba4", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "deleteRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "696f370392fe0b0067317511", + "sourceDigest": "6660816a22798ea565fbaad556338f8c034bc8e6c9ff5b482d62cf2480f36f81", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69787c4d96d5c1006802a2b9", + "sourceDigest": "a93a784a4b26429579a07175655debb5ad28369656a1a9306ac2236490a25b71", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "rowHierarchyType", + "widthMode", + "editor", + "indicatorsAsCol" + ], + "methodSignals": [ + "changeCellValue" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6979f44b20f246006732267e", + "sourceDigest": "b94a39e1dddaeffda683b6401240c7884e54e1ceafd7bcf05ad98fb1498376f7", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "legends" + ], + "methodSignals": [ + "on" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "697f0e81cfeff4005eb02fa4", + "sourceDigest": "37a85932e8b25705973f6df515f0d932e66efb259d534d315c674dc6f887f8fb", + "family": "pivot-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "showSort", + "legends" + ], + "methodSignals": [ + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "69819e57c4422900689313aa", + "sourceDigest": "ce638d7a068801e6b67f32c325f8fa098c4a1a3a2bfa059780f4dd3fc5422a04", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [ + "dragHeaderMode", + "widthMode", + "heightMode", + "cellType", + "select", + "disableSelect", + "indicatorsAsCol", + "legends" + ], + "methodSignals": [ + "on" + ], + "chartTypes": [ + "bar" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6982e5a97a558400611ce04b", + "sourceDigest": "184e7dfdc42ea006aa33accb2ceb0755f1c985ba03f3ea42f7ec38bb3d83081d", + "family": "sheet", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "addRecords", + "changeCellValue", + "getCellValue", + "release", + "setCellContent" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "69899af7657c7a005c098ad8", + "sourceDigest": "d60d6adf34a3d6cd94e04b2849436a1deab38c8a499773fa73573b0aaebf8138", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "circlepacking" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69a6c05d547bee005d6c847b", + "sourceDigest": "9098bfe3b595d4f3ebb318bc7d7533f6310c17ba545de6d088dc432caff3e64f", + "family": "pivot-chart", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [], + "chartTypes": [ + "line" + ], + "actionKinds": [], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "69c23daa709fdc006857f1c8", + "sourceDigest": "61ca69dc7d768cd22c1b8270e841ee9ab376a4bdeab0ee926ae029339951e6fe", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "move" + ], + "status": "migrated", + "priority": null, + "localCase": "frozen-scroll-columns", + "verification": "frozenHorizontalBarPos + rightFrozenHorizontalBarPos" + }, + { + "id": "69d614f2e41b43005d89a624", + "sourceDigest": "aa5d52c34644c5012f725b6444a7ffef432a2d4a0fd3a783241279dd70ff4c54", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "headerHierarchyType", + "headerExpandLevel", + "fillHandle", + "widthMode" + ], + "methodSignals": [], + "chartTypes": [], + "actionKinds": [ + "click", + "drag" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6a1416f2709fdc006857f1dc", + "sourceDigest": "d10cb860c5db798b01a81c86e9d47c2efaa5b4a3ef3db104b8aa7cc0b96227e9", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "widthMode", + "heightMode", + "select", + "headerSelectMode", + "highlightMode" + ], + "methodSignals": [ + "selectCell", + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6a68957b3dd664005e729649", + "sourceDigest": "50cf110bf7ca31165743a1cdedb29acaa341c5b1987f1f559752cc24ce3f0f0f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 2, + "optionSignals": [ + "cellType" + ], + "methodSignals": [ + "getCheckboxState", + "on", + "release" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "migrated", + "priority": null, + "localCase": "tree-checkbox-record-index-clear", + "verification": "checkedState" + }, + { + "id": "6a69af4d02c575005f77ab2c", + "sourceDigest": "cdc21462d11630f0367d47d38dc98dbc62da53a1f191abb51668033c1b78b900", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode" + ], + "methodSignals": [ + "release", + "updateOption" + ], + "chartTypes": [], + "actionKinds": [], + "status": "migrated", + "priority": null, + "localCase": "tree-zero-height-toggle", + "verification": "getRowHeight + renderedHeight" + }, + { + "id": "6a69f6177406d0005d72f226", + "sourceDigest": "92064e6744d9516d5be4ba77b9ec748dc84887f1e578007c613a188675122caa", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "bottomFrozenRowCount" + ], + "methodSignals": [ + "release", + "setRecords" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6a6af1ccbfb525005fed69dc", + "sourceDigest": "b39f1bb4798f2b8bb21527f773d3888cd44a042415fa986a28adeaaac1af298d", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [], + "methodSignals": [ + "release", + "updateSortState" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6a82f7a71d0efd005e397e9d", + "sourceDigest": "33a1aa5a5eae772a3f7e43cb69109a622e702e3607d54add81b94ac756daca07", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "cellType", + "frozenColCount", + "rightFrozenColCount", + "bottomFrozenRowCount", + "rowSeriesNumber" + ], + "methodSignals": [ + "on", + "setRecords", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6a8597d0a44900005e2b8e47", + "sourceDigest": "76a134f6859a94ec067736abfa5346b83eff832bef5b44e7a148cff0f3c4b7a8", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "heightMode", + "cellType" + ], + "methodSignals": [ + "release", + "setScrollTop" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6a8c044f1d0efd005e397e9f", + "sourceDigest": "089395b7afdf31425e3f72179af5b3ad73c7c5c825261cca94a9a37be4f07c4f", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "editor" + ], + "methodSignals": [ + "getCellValue", + "release", + "selectCell" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6a8c044fe9ec270069f957ea", + "sourceDigest": "aef0f9c3de5b824692db3ecfc5fd385bd985f2a2e4909b66b9073a3c158c2f67", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "editor" + ], + "methodSignals": [ + "getCellOriginValue", + "getCellValue", + "release", + "selectCell", + "selectCells" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6aa3b008d1dbbb005e7d9500", + "sourceDigest": "98c52656101af16155b4120b2ed50275ac791fe579894a2508a6b15948fcc172", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode" + ], + "methodSignals": [ + "changeCellValue", + "getCellValue", + "release" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6aaa79209c5d40005e364d42", + "sourceDigest": "d90fb5e87cd766240595562b2f81d63d291c8f3d5543b48a08ce27a4bf9bb3d7", + "family": "list-table", + "sourceBucket": "needs_complex_source_review", + "recordedInteractions": 1, + "optionSignals": [ + "heightMode" + ], + "methodSignals": [ + "changeCellValue", + "on", + "release" + ], + "chartTypes": [], + "actionKinds": [ + "click" + ], + "status": "deferred_large_source", + "priority": "P2", + "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + }, + { + "id": "6aaba81349fc4f005c341b4c", + "sourceDigest": "7e293d685765164cca2aaea50799d20093ee0d06796fef6cc1abf91c84ed5119", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 1, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount" + ], + "methodSignals": [ + "release", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [ + "click", + "move" + ], + "status": "deferred_interaction", + "priority": "P1", + "reason": "recorded actions have no proven matching local action and assertion" + }, + { + "id": "6aaba81349fc4f005c341b4d", + "sourceDigest": "5e49311ed620fb8594ed23059c791de560deb9a556bc5b8df41a2796bf669d4c", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount" + ], + "methodSignals": [ + "release", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + }, + { + "id": "6aaba8136d3a95005dc7fa6e", + "sourceDigest": "9549a4eca5c1069aa68af878d0a93062eaf35cd0c0fdad03712bbb14e6b11bb2", + "family": "list-table", + "sourceBucket": "public_candidate", + "recordedInteractions": 0, + "optionSignals": [ + "widthMode", + "frozenColCount", + "rightFrozenColCount" + ], + "methodSignals": [ + "release", + "setScrollLeft" + ], + "chartTypes": [], + "actionKinds": [], + "status": "deferred_static", + "priority": "P2", + "reason": "configuration or data variant has no proven matching local assertion" + } + ] +} diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md new file mode 100644 index 0000000000..329376964b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -0,0 +1,37 @@ +# 本地视觉用例覆盖 + +本清单描述当前本地用例的实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 + +| 功能 | 当前代表用例 | 主要条件 | +| --- | --- | --- | +| 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | +| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | +| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | +| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | +| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | +| Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | +| Sheet | `sheet-add-columns`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列插入、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | +| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | +| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动 | +| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | +| 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | + +Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 + +## BugServer 未选候选去向(2026-09-24) + +上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 20 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 + +| 去向 | 数量 | 含义 | +| --- | ---: | --- | +| 已迁入本地用例 | 20 | 13 个新模块,以匿名数据重建配置及动作 | +| 隐私风险排除 | 7 | 发现业务化字段或数值,原始内容没有进入仓库 | +| 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | +| 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | +| 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | +| 交互未证明覆盖 | 176 | 录制动作缺少对应的本地动作与断言 | +| 静态配置未证明覆盖 | 223 | 配置或数据变体缺少对应的本地断言 | + +本轮新增可验证场景:列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 + +这份台账是可继续处理的缺口清单,尚不能据此判断 BugServer 用例迁移已经完成。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 diff --git a/packages/vtable/__tests__/visual/cases/README.md b/packages/vtable/__tests__/visual/cases/README.md new file mode 100644 index 0000000000..78f42719ba --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/README.md @@ -0,0 +1,21 @@ +# VTable 视觉用例 + +`index.mjs` 是唯一可执行清单;一份用例一个模块,按主要验证目的归类。用 `--list` 查看实际 ID、目的和文件路径;已覆盖的条件与缺口见 [覆盖清单](./COVERAGE.md)。下表用于选择相关范围,交互动作仍放在所属功能目录。 + +| 目录 | 主要覆盖 | +| --- | --- | +| `table`、`header`、`cells` | 列表基础、表头层级、单元格类型与格式 | +| `pivot`、`pivot-chart` | 透视维度、虚拟节点、透视图 | +| `gantt`、`sheet`、`plugins` | 扩展包的图形与 API | +| `layout`、`frozen`、`scroll`、`empty`、`theme` | 尺寸、冻结、滚动、空状态、主题 | +| `interaction`、`keyboard`、`edit`、`sort`、`menu` | 选择、编辑、排序 | +| `analysis`、`records`、`transpose` | 聚合、过滤、记录更新、转置 | +| `components`、`custom`、`language`、`tree`、`data`、`group`、`style`、`api` | 标题、自定义布局、多语言 | + +新增用例先查找已有近邻,优先在一个明确场景中补强必要条件。模块默认导出 `mount(container)`、`verify(page)` 和可选 `exercise(page)`;`mount` 返回待测实例。输入必须固定、公开、无外网依赖。`exercise` 需要执行真实动作,`verify` 需要检查目标状态;截图负责外观,不能替代语义断言。模块和核心方法写中文目的注释。登记唯一短 ID、目的、文件及所需 `bundles`;未登记模块不会执行。 + +迁移模块头部使用 `BugServer case IDs: <真实ID>`;合并时列出全部真实来源 ID,改写时仍保留原 ID。该 ID 仅用于追溯,不表示与线上内容实时同步。开发者新建的本地用例不填空值或占位 ID,待后续反向同步成功后再写入服务返回的真实 ID。不得复制业务原文、内部地址、凭证、原始数据或截图到公开仓库;来源不明时先放在私有复核目录。 + +BugServer 未提供 `interactions` 字段时,仅表示没有附加录制动作。仍须检查源码中的事件、定时器、异步调用、构建后的 API 更新及资源。迁移时保留目标配置、数据边界、动作顺序和最终状态;只改写无关宿主与业务内容。本目录只保存脱敏的 [候选去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json);原始 BugServer 来源、完整筛选台账和待审记录保存在仓库外私有目录。 + +新增或修改后先运行单例 `--self-compare --case `,再运行对应目录;提交前运行默认全量比较。若用例在官方基线不支持,报告为执行错误,应如实说明,不能把自比较当作双侧通过。 diff --git a/packages/vtable/__tests__/visual/cases/analysis/aggregation-float.mjs b/packages/vtable/__tests__/visual/cases/analysis/aggregation-float.mjs new file mode 100644 index 0000000000..5a7d8628d2 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/analysis/aggregation-float.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 69d89a775bd8c7005e123da1 + * 验证目的:小数数据的 AVG 与顶部 SUM 聚合在同一列表中显示。 + * 改写:原例的未声明变量和错误释放调用改为直接返回实例。 + */ +export default { + mount(container) { + // 用 0.1 与 0.2 触发浮点聚合,保留顶部和底部聚合位置。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'value', title: 'Value', width: 120, aggregation: [ + { aggregationType: window.VTable.TYPES.AggregationType.AVG }, + { aggregationType: window.VTable.TYPES.AggregationType.SUM, showOnTop: true } + ] }], + records: [{ value: 0.1 }, { value: 0.2 }], + bottomFrozenRowCount: 3, widthMode: 'autoWidth', heightMode: 'autoHeight', autoWrapText: true + }); + }, + async verify(page) { + // 小数记录和聚合行均存在,外观及聚合文本交给截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount < 5 || table.getCellOriginValue(0, 2) !== 0.1) + throw new Error('聚合行或小数记录缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/analysis/aggregation-pagination.mjs b/packages/vtable/__tests__/visual/cases/analysis/aggregation-pagination.mjs new file mode 100644 index 0000000000..8ae4857333 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/analysis/aggregation-pagination.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 65ed9e7aa5483e00afa5869c + * 验证目的:同值合并、SUM 聚合和每页两条记录的分页共同显示。 + * 改写:商品名称换成通用项,保留来源的 100/1/1/2/2/2 数值关系。 + */ +export default { + mount(container) { + // 固定六条记录,第一页包含 100 与 1,聚合总和可见。 + return new window.VTable.ListTable(container, { + records: [100, 1, 1, 2, 2, 2].map((price, index) => ({ area: 'A', product: `Item ${index + 1}`, price })), + columns: [ + { field: 'area', title: 'Area', width: 'auto', mergeCell: true, + aggregation: [{ aggregationType: window.VTable.TYPES.AggregationType.NONE, formatFun: () => 'Total' }] }, + { field: 'product', title: 'Product', width: 'auto' }, + { field: 'price', title: 'Price', width: 'auto', + aggregation: [{ aggregationType: window.VTable.TYPES.AggregationType.SUM, + formatFun: value => Math.round(value) }] } + ], + widthMode: 'standard', pagination: { perPageCount: 2, currentPage: 0 } + }); + }, + async verify(page) { + // 检查分页数据与数值聚合在可见表格中出现。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellValue(col, row)); + if (!values.includes('Item 1') || !values.includes('Item 2') || values.includes('Item 3')) + throw new Error('分页记录错误'); + if (!values.some(value => Number(value) === 101 || Number(value) === 108)) + throw new Error('SUM 聚合缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/analysis/filter-api.mjs b/packages/vtable/__tests__/visual/cases/analysis/filter-api.mjs new file mode 100644 index 0000000000..3e6013130c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/analysis/filter-api.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 65bf7a3197cc3d008de5b474 + * 验证目的:字段枚举筛选和函数筛选同时应用于列表。 + * 改写:用通用编号和状态替换人员信息,并缩小数据量以便本地稳定运行。 + */ +export default { + mount(container) { + // 60 条固定记录的交集是 10 条,便于直接验证筛选结果。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, { field: 'state', title: 'State', width: 120 }, + { field: 'name', title: 'Name', width: 150 }], + records: Array.from({ length: 60 }, (_, i) => ({ id: i + 1, state: i % 2 === 0 ? 'A' : 'B', name: `Item ${i + 1}` })), + frozenColCount: 1, widthMode: 'standard' + }); + table.updateFilterRules([{ filterKey: 'state', filteredValues: ['A'] }, + { filterFunc: record => record.id % 3 === 0 }]); + return table; + }, + async verify(page) { + // 两个过滤条件应同时生效,且首条可见记录符合交集。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount !== 11 || table.getCellValue(0, 1) !== 3) + throw new Error(`筛选结果错误:${table.rowCount}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/api/update-columns.mjs b/packages/vtable/__tests__/visual/cases/api/update-columns.mjs new file mode 100644 index 0000000000..88eb7aa6ad --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/api/update-columns.mjs @@ -0,0 +1,25 @@ +/** + * BugServer case IDs: 65656abf7bb49c240fa99c78 + * 验证目的:悬停状态存在时 updateColumns 增加重复字段列。 + * 改写:展示字段换成通用项,保留更新时机与新增列结构。 + */ +export default { + mount(container) { + // 先设置悬停位置,再追加第二列同字段 Name。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, { field: 'name', title: 'Name', width: 150 }], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }] + }); + table.stateManager.updateHoverPos(2, 2); + table.updateColumns([...table.columns, { field: 'name', title: 'Name copy', width: 150 }]); + return table; + }, + async verify(page) { + // 重复字段新列应正确读取原记录。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 4 || table.getCellValue(3, 1) !== 'A') throw new Error('列更新失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/checkbox-states.mjs b/packages/vtable/__tests__/visual/cases/cells/checkbox-states.mjs new file mode 100644 index 0000000000..7b5516fded --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/checkbox-states.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 653b222c1053b2a37d5dc9a7 + * 验证目的:复选框对象值的选中、禁用与布尔值状态正确初始化。 + * 改写:保留来源的状态组合,缩减无关的文本与排序列。 + */ +export default { + mount(container) { + // 覆盖未选、已选、禁用和直接布尔值四种输入形态。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'check', title: 'Check', width: 130, headerType: 'checkbox', cellType: 'checkbox' }, + { field: 'label', title: 'Label', width: 150 } + ], + records: [ + { check: { text: 'unchecked', checked: false, disable: false }, label: 'A' }, + { check: { text: 'unchecked', checked: false, disable: true }, label: 'B' }, + { check: { text: 'checked', checked: true, disable: false }, label: 'C' }, + { check: { text: 'checked', checked: true, disable: true }, label: 'D' }, + { check: true, label: 'E' }, { check: false, label: 'F' } + ], + frozenColCount: 1, widthMode: 'standard' + }); + }, + async verify(page) { + // 用公开状态 API 验证两种初始状态,而非只检查配置对象。 + await page.evaluate(() => { + const table = window.__visualTable; + const states = table.getCheckboxState('check'); + if (table.getCellType(0, 1) !== 'checkbox' || states.length !== 6) + throw new Error('复选框未初始化'); + if (table.getCellCheckboxState(0, 1) !== false || table.getCellCheckboxState(0, 3) !== true) + throw new Error('复选框初始状态错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/inline-image.mjs b/packages/vtable/__tests__/visual/cases/cells/inline-image.mjs new file mode 100644 index 0000000000..bd54994637 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/inline-image.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 64744ff55d221c008666ee12 + * 验证目的:图片单元格自动尺寸、保持宽高比,点击图片边缘不报错。 + * 改写:将远程动物照片替换为本地内联图形,保留不同图片比例与录制点击。 + */ +export default { + mount(container) { + // 内联图形避免公开测试依赖远程图片服务。 + const svg = (width, height, color) => `data:image/svg+xml,${encodeURIComponent(``)}`; + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'image', title: 'Image', width: 300, cellType: 'image', keepAspectRatio: true, + imageAutoSizing: true, style: { padding: 1 } }], + records: [{ id: 1, image: svg(100, 50, '#75aadb') }, + { id: 2, image: svg(50, 100, '#e8af6f') }, { id: 3, image: svg(100, 100, '#82bd84') }] + }); + }, + async exercise(page) { + // 录制动作指向图片边框内侧,目标定位随当前单元格尺寸计算。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 15, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 边框点击不应损坏图片字段或选择状态。 + await page.evaluate(() => { + const table = window.__visualTable; + if (!table.getCellValue(1, 1).startsWith('data:image/svg+xml')) throw new Error('图片字段缺失'); + if (!table.getSelectedCellRanges().length) throw new Error('图片边缘点击未选中单元格'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/mixed-sparkline-progress.mjs b/packages/vtable/__tests__/visual/cases/cells/mixed-sparkline-progress.mjs new file mode 100644 index 0000000000..a6f83ef550 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/mixed-sparkline-progress.mjs @@ -0,0 +1,34 @@ +/** + * BugServer case IDs: 65d2ffbb97cc3d008de5b570, 65fc11f6603de700d1d8bacf, 65fbd5707c3a0c00c99f2eb9 + * 验证目的:同一列按行切换 sparkline、progressbar 与文本,负值进度条仍显示。 + * 改写:缩小颜色定义与数据量,合并两例 row-height;保留行类型分支、负值范围与自动行高。 + */ +export default { + mount(container) { + // 记录顺序对应来源的 1/2/3 行类型分支。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'percent', title: 'Percent', width: 150, + cellType: args => args.row % 3 === 0 ? 'text' : args.row % 2 === 0 ? 'progressbar' : 'sparkline', + sparklineSpec: { type: 'line', smooth: true, pointShowRule: 'all', line: { style: { stroke: '#2E62F1', strokeWidth: 2 } } } }, + { field: 'value', title: 'Axis', width: 120, cellType: 'progressbar', min: -10, max: 20, + barType: 'negative', style: { barHeight: 20, barBottom: 7, textAlign: 'right' } } + ], + records: [ + { percent: [30, 40, 50, 30, 50], value: 20 }, + { percent: '80%', value: 18 }, + { percent: 'Text', value: -10 } + ], + widthMode: 'standard', heightMode: 'autoHeight' + }); + }, + async verify(page) { + // 检查动态类型真正按行分配,并确认负值数据未丢失。 + await page.evaluate(() => { + const table = window.__visualTable; + const types = [1, 2, 3].map(row => table.getCellType(0, row)); + if (types.join(',') !== 'sparkline,progressbar,text') throw new Error(`行类型错误:${types}`); + if (table.getCellOriginValue(1, 3) !== -10) throw new Error('负值记录缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/switch-button.mjs b/packages/vtable/__tests__/visual/cases/cells/switch-button.mjs new file mode 100644 index 0000000000..ac25afd9a8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/switch-button.mjs @@ -0,0 +1,34 @@ +/** + * BugServer case IDs: 67b823fc88790a00ae624ae3, 67b829a64d4ded00b2f12762 + * 验证目的:开关与按钮列同时覆盖普通、默认选中和禁用视觉状态。 + * 改写:合并两个使用相同记录结构的示例,保留各自的核心列配置。 + */ +export default { + mount(container) { + // 保留对象值开关和列级 checked/disable 两类来源条件。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'value', title: 'Value', width: 100 }, + { field: 'switch', title: 'Switch', width: 110, cellType: 'switch', checkedText: 'on', uncheckedText: 'off' }, + { field: 'switch1', title: 'Checked', width: 110, cellType: 'switch', checked: true, checkedText: 'on', uncheckedText: 'off' }, + { field: 'switch2', title: 'Disabled', width: 110, cellType: 'switch', checked: true, disable: true }, + { field: 'button', title: 'Button', width: 110, cellType: 'button', text: 'click' }, + { field: 'button', title: 'Disabled button', width: 130, cellType: 'button', disable: true, text: 'click' } + ], + records: [ + { value: 20 }, { value: 18 }, { value: 12, switch: { checked: true, disable: true } }, + { value: 10 }, { value: -10 } + ], + widthMode: 'standard', defaultRowHeight: 80, heightMode: 'autoHeight' + }); + }, + async verify(page) { + // 验证渲染类型和来源对象的选中状态,其他外观由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellType(1, 3) !== 'switch' || table.getCellType(4, 3) !== 'button') + throw new Error('开关或按钮列类型错误'); + if (table.getCellSwitchState(1, 3) !== true) throw new Error('开关状态错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/wrapped-text.mjs b/packages/vtable/__tests__/visual/cases/cells/wrapped-text.mjs new file mode 100644 index 0000000000..03d4290c5c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/wrapped-text.mjs @@ -0,0 +1,31 @@ +/** + * BugServer case IDs: 64744f315d221c008666ee10 + * 验证目的:字段格式化后的长文本和显式换行在自动行高下显示。 + * 改写:删除与换行无关的排序回调,保留格式化、autoWrapText 和 enableLineBreak。 + */ +export default { + mount(container) { + // 固定多行记录,使长文本及显式换行都进入可见区域。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, style: { autoWrapText: true }, + fieldFormat: record => `Completed completed completed ${record.progress}%` }, + { field: 'id', title: 'ID', width: 150, + fieldFormat: record => `Line one\nLine two ${record.id}` }, + { field: 'name', title: 'Name', width: 150 } + ], + records: Array.from({ length: 10 }, (_, index) => ({ progress: index, id: index + 1, name: 'name' })), + widthMode: 'standard', heightMode: 'autoHeight', defaultRowHeight: 50, + autoWrapText: true, enableLineBreak: true + }); + }, + async verify(page) { + // 同时检查格式化文字与表格的有效行高。 + await page.evaluate(() => { + const table = window.__visualTable; + if (!String(table.getCellValue(0, 1)).includes('Completed')) throw new Error('格式化文本缺失'); + if (!String(table.getCellValue(1, 1)).includes('\n')) throw new Error('显式换行缺失'); + if (table.getRowHeight(1) < 50) throw new Error('自动行高未生效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/components/hover-tooltip.mjs b/packages/vtable/__tests__/visual/cases/components/hover-tooltip.mjs new file mode 100644 index 0000000000..29c637adee --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/components/hover-tooltip.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 64f81f827d8f46008b2df45e + * 验证目的:鼠标依次经过两个进度条单元格时,showTooltip 更新内容。 + * 改写:缩短动态图标和数据,保留 mouseenter_cell、showTooltip 与两次悬停。 + */ +export default { + mount(container) { + // 事件处理使用当前单元格值,第二次悬停必须替换第一次内容。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'value', title: 'Value', width: 120 }, + { field: 'percent', title: 'Progress', width: 160, cellType: 'progressbar' }], + records: [{ value: 20, percent: '80%' }, { value: 10, percent: '40%' }] + }); + table.on('mouseenter_cell', ({ col, row }) => { + const rect = table.getVisibleCellRangeRelativeRect({ col, row }); + table.showTooltip(col, row, { content: `cell data: ${table.getCellValue(col, row)}`, + referencePosition: { rect, placement: window.VTable.TYPES.Placement.right }, + className: 'visual-tooltip', style: { bgColor: 'black', color: 'white', arrowMark: true } }); + }); + return table; + }, + async exercise(page) { + // 两个坐标都来自表格矩形,分别断言悬停后真实浮层文本。 + for (const row of [1, 2]) { + const point = await page.evaluate(row => { + const b = window.__visualTable.getCellRect(0, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, row); + await page.mouse.move(point.x, point.y); + await page.waitForFunction(value => document.body.innerText.includes(`cell data: ${value}`), row === 1 ? 20 : 10); + } + }, + async verify(page) { + // 最终提示应显示第二行的值。 + await page.evaluate(() => { + if (!document.body.innerText.includes('cell data: 10')) throw new Error('提示内容未更新'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/components/legend-resize.mjs b/packages/vtable/__tests__/visual/cases/components/legend-resize.mjs new file mode 100644 index 0000000000..30ffba7757 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/components/legend-resize.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 672b4d9ae4bb4400b299cbce + * 验证目的:顶部单行图例与标题共存时,宿主缩窄后组件继续正常布局。 + * 改写:图例标签改为通用类别,保留 maxRow、标题和 800 到 300 像素变宽过程。 + */ +export default { + mount(container) { + // 宿主先以宽布局挂载,然后模拟来源中的窄容器更新。 + container.style.width = '800px'; + container.style.height = '400px'; + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'count', title: 'Count', width: 150 }, + { field: 'id', title: 'ID', width: 100 }], + records: [{ count: 10, id: 1 }, { count: 20, id: 2 }], + legends: { data: ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta'].map((label, i) => + ({ label, shape: { fill: ['#2E62F1', '#4DC36A', '#FF8406'][i % 3], symbolType: 'circle' } })), + orient: 'top', position: 'start', maxRow: 1, padding: [50, 0, 0, 0] }, + title: { text: 'Legend Resize', align: 'center', subtext: 'Narrow container', orient: 'top', padding: 40 } + }); + container.style.width = '300px'; + container.style.height = '300px'; + return table; + }, + async verify(page) { + // 缩窄后宿主宽度和末条数据均有效;组件布局由截图判断。 + await page.evaluate(() => { + const table = window.__visualTable; + if (document.getElementById('table').getBoundingClientRect().width !== 300 || + table.getCellValue(0, 2) !== 20) + throw new Error('图例缩窄场景无效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/components/title.mjs b/packages/vtable/__tests__/visual/cases/components/title.mjs new file mode 100644 index 0000000000..8e2cd8ced4 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/components/title.mjs @@ -0,0 +1,39 @@ +/** + * BugServer case IDs: 64ba680378943290ce95d080 + * 验证目的:顶部标题、副标题和表格表头布局正确,录制的表头点击可用。 + * 改写:标题和记录换成通用内容,点击点由表头矩形计算。 + */ +export default { + mount(container) { + // 保留标题顶部方向、内边距与换行副标题。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true, + fieldFormat: record => `${record.progress}%` }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 50, id: 2, name: 'B' }], + title: { text: 'Table title', align: 'left', subtext: 'Subtitle line 1\nSubtitle line 2', orient: 'top', padding: 40 }, + widthMode: 'standard' + }); + }, + async exercise(page) { + // 按录制动作点击首列表头,但使用当前布局的矩形坐标。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(0, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 标题占位和首列内容均应在表格中。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== '100%') throw new Error('标题下表格内容缺失'); + if (!table.internalProps.title?.getComponentGraphic()?.AABBBounds.height() || table.tableY <= 0) + throw new Error('标题未占顶部空间'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/custom/progress-layout.mjs b/packages/vtable/__tests__/visual/cases/custom/progress-layout.mjs new file mode 100644 index 0000000000..b34b6ca30c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/custom/progress-layout.mjs @@ -0,0 +1,42 @@ +/** + * BugServer case IDs: 67ac6b4ddb3b0800b20431e5 + * 验证目的:动态图标、分段进度条、负值进度条与自定义布局共同渲染。 + * 改写:将长 SVG 缩成内联箭头,保留回调结构与不同进度值。 + */ +export default { + mount(container) { + // 用固定记录触发所有颜色分支和自定义布局回调。 + window.__customLayoutCalls = 0; + const VTable = window.VTable; + return new VTable.ListTable(container, { + columns: [ + { field: 'value', title: 'Icon', width: 90, + style: { color: data => Number(data.value) > 0 ? '#50aa53' : '#d85859' }, + icon: () => ({ type: 'svg', svg: '', width: 12, height: 12, name: 'arrow', positionType: VTable.TYPES.IconPosition.right }) }, + { field: 'percent', title: 'Progress', width: 140, cellType: 'progressbar', + style: { barHeight: 20, barColor: data => Number.parseInt(data.dataValue, 10) > 50 ? '#4dbd74' : '#ffc107' } }, + { field: 'percent', title: 'Custom', width: 180, cellType: 'progressbar', + customLayout: ({ table, col, row, rect }) => { + window.__customLayoutCalls++; + const record = table.getRecordByCell(col, row); + const bounds = rect ?? table.getCellRect(col, row); + const rootContainer = new VTable.CustomLayout.Container({ width: bounds.width, height: bounds.height }); + rootContainer.add(new VTable.CustomLayout.Text({ text: `${record.percent} : ${record.value}`, fontSize: 13, fill: 'black', marginLeft: 10 })); + return { rootContainer }; + } }, + { field: 'value', title: 'Negative axis', width: 140, cellType: 'progressbar', min: -10, max: 20, + barType: 'negative', style: { barHeight: 20, barBottom: 7, textAlign: 'right' } } + ], + records: [{ percent: '100%', value: 20 }, { percent: '60%', value: 12 }, + { percent: '20%', value: 4 }, { percent: '0%', value: -10 }], + showFrozenIcon: true, allowFrozenColCount: 2, widthMode: 'standard' + }); + }, + async verify(page) { + // 自定义布局必须执行,负值记录必须保留。 + await page.evaluate(() => { + if (window.__customLayoutCalls < 4) throw new Error('自定义布局未执行'); + if (window.__visualTable.getCellOriginValue(3, 4) !== -10) throw new Error('负值进度条记录缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/data/nested-field.mjs b/packages/vtable/__tests__/visual/cases/data/nested-field.mjs new file mode 100644 index 0000000000..f024caa257 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/data/nested-field.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 6720b9ea30877400b3e630d7 + * 验证目的:数组形式字段路径读取嵌套值,缺失路径不使表格失败。 + * 改写:将文字改为通用项,保留第三条缺失嵌套对象。 + */ +export default { + mount(container) { + // 第三条不包含 type,验证字段路径的缺失值分支。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 120, sort: true }, + { field: 'age', title: 'Age', width: 100, sort: true }, + { field: ['type', 'name'], title: 'Type', width: 130, sort: true }], + records: [{ name: 'A', age: 12, type: { name: 'One' } }, + { name: 'B', age: 42, type: { name: 'Two' } }, { name: 'C', age: 42 }], + widthMode: 'standard' + }); + }, + async verify(page) { + // 有值与缺值两条路径都应返回预期结果。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(2, 1) !== 'One' || table.getCellValue(2, 3)) + throw new Error('嵌套字段读取错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/data/promise-custom-merge.mjs b/packages/vtable/__tests__/visual/cases/data/promise-custom-merge.mjs new file mode 100644 index 0000000000..e83e9bed3c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/data/promise-custom-merge.mjs @@ -0,0 +1,50 @@ +/** + * BugServer case IDs: 65671306eb24adef19a3a669 + * 验证目的:CachedDataSource 异步批次加载与多行多列 customMergeCell 同时生效。 + * 改写:移除人员联系方式及职业信息,保留 Promise 缓存、合并区域和滚动位置。 + */ +export default { + mount(container) { + // 按批次缓存同一个 Promise,固定数据避免远程请求与时间波动。 + const batches = new Map(); + const source = new window.VTable.data.CachedDataSource({ + get(index) { + // 每 20 条记录共用一次异步生成,模拟原始来源的分页获取。 + const start = Math.floor(index / 20) * 20; + if (!batches.has(start)) batches.set(start, new Promise(resolve => { + setTimeout(() => resolve(Array.from({ length: 20 }, (_, offset) => ({ + id: start + offset + 1, label: `Item ${start + offset + 1}`, + group: `Group ${(start + offset) % 3 + 1}`, date: '2024-01-01' + }))), 30); + })); + return batches.get(start).then(records => records[index - start]); + }, + length: 200 + }); + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'label', title: 'Label', width: 170 }, + { field: 'group', title: 'Group', width: 170 }, + { field: 'date', title: 'Date', width: 150 }], + customMergeCell: (col, row) => { + // 第 8-10 行的三列使用与 BugServer 来源相同的合并边界。 + if (col < 1 || col > 3 || row < 8 || row > 10) return undefined; + return { text: 'Merged async rows', range: { start: { col: 1, row: 8 }, + end: { col: 3, row: 10 } }, style: { bgColor: '#ccddee' } }; + } + }); + table.dataSource = source; + table.setScrollTop(60); + return table; + }, + async verify(page) { + // 等待异步批次完成,并确认合并区域在可见行内有效。 + await page.waitForFunction(() => window.__visualTable.getCellValue(0, 8) === 8); + await page.evaluate(() => { + const table = window.__visualTable; + const merge = table.getCellRange(1, 8); + if (merge?.start?.col !== 1 || merge?.end?.col !== 3 || merge?.end?.row !== 10) + throw new Error(`异步合并区域错误:${JSON.stringify(merge)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/data/promise-keep-data.mjs b/packages/vtable/__tests__/visual/cases/data/promise-keep-data.mjs new file mode 100644 index 0000000000..7e351f2891 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/data/promise-keep-data.mjs @@ -0,0 +1,39 @@ +/** + * BugServer case IDs: 6806172028b4c200a9da9987 + * 验证目的:CachedDataSource 挂载后 updateOption({keepData:true}) 保留异步数据。 + * 改写:去除邮箱、电话和人员字段,改用同步可重复的批次 Promise。 + */ +export default { + mount(container) { + // 同一缓存批次为相邻行返回稳定记录。 + const source = new window.VTable.data.CachedDataSource({ + length: 20, + get(index) { + // 每次请求按索引返回同一条固定记录。 + return Promise.resolve({ id: index + 1, label: `Item ${index + 1}` }); + } + }); + const columns = [{ field: 'id', title: 'ID', width: 100 }, + { field: 'label', title: 'Label', width: 180 }]; + const table = new window.VTable.ListTable(container, { columns }); + table.dataSource = source; + window.__keepDataColumns = columns; + return table; + }, + async exercise(page) { + // 首行数据加载后更新列配置,复用既有数据源。 + await page.waitForFunction(() => window.__visualTable.getCellValue(0, 1) === 1); + await page.evaluate(() => { + window.__visualTable.updateOption({ columns: window.__keepDataColumns }, { keepData: true }); + }); + }, + async verify(page) { + // 更新后仍能读取首行与后续异步行。 + await page.waitForFunction(() => window.__visualTable.getCellValue(0, 2) === 2); + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(1, 1) !== 'Item 1' || table.getCellValue(1, 2) !== 'Item 2') + throw new Error('updateOption 丢失 CachedDataSource 数据'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/data/promise-source.mjs b/packages/vtable/__tests__/visual/cases/data/promise-source.mjs new file mode 100644 index 0000000000..2d7ca6a023 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/data/promise-source.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 6565ca7e4c6c1a77d0efcc76 + * 验证目的:CachedDataSource 的异步 get 按批次加载可见行。 + * 改写:用固定编号代替人员信息,缩短模拟请求等待;保留 Promise 与批次缓存。 + */ +export default { + mount(container) { + // 每 20 行只创建一个 Promise,模拟来源的分批异步数据。 + const loaded = new Map(); + const source = new window.VTable.data.CachedDataSource({ + get(index) { + const start = Math.floor(index / 20) * 20; + if (!loaded.has(start)) loaded.set(start, new Promise(resolve => { + setTimeout(() => resolve(Array.from({ length: 20 }, (_, offset) => ({ id: start + offset + 1, name: `Item ${start + offset + 1}` }))), 30); + })); + return loaded.get(start).then(records => records[index - start]); + }, + length: 100 + }); + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 120 }, { field: 'name', title: 'Name', width: 180 }] + }); + table.dataSource = source; + return table; + }, + async verify(page) { + // 等待异步首批数据进入画布,不能以固定 sleep 代替。 + await page.waitForFunction(() => window.__visualTable.getCellValue(0, 1) === 1); + await page.evaluate(() => { + if (window.__visualTable.getCellValue(1, 1) !== 'Item 1') throw new Error('异步数据未加载'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/edit/complete-input.mjs b/packages/vtable/__tests__/visual/cases/edit/complete-input.mjs new file mode 100644 index 0000000000..9d1070f060 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/edit/complete-input.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 656856014c3611faee9b1a5c + * 验证目的:输入编辑器写入新值并调用 completeEditCell 后记录被更新。 + * 改写:本地加载编辑器,保留来源通过 getEditor.element 修改值的路径。 + */ +export default { + mount(container) { + // 第二条记录的 id 初始缺失,编辑完成后应成为明确的新值。 + const VTable = window.VTable; + VTable.register.editor('input-editor', new VTable.editors.InputEditor({})); + const table = new VTable.ListTable(container, { + columns: [ + { field: 'name', title: 'Name', width: 150 }, + { field: 'date', title: 'Date', width: 150 }, + { field: 'id', title: 'ID', width: 100, editor: 'input-editor' } + ], + records: [{ name: 'A', date: '2019-01-01', id: 1 }, + { name: 'B', date: '2010-11-01' }, { name: 'C', date: '2013-10-20', id: 3 }] + }); + table.startEditCell(2, 2); + const editor = table.getEditor(2, 2); + if (!editor?.element) throw new Error('输入编辑器没有挂载'); + editor.element.value = '11111'; + table.completeEditCell(); + return table; + }, + async verify(page) { + // 检查真实记录值,防止只在编辑框中显示新值而未提交。 + await page.evaluate(() => { + const table = window.__visualTable; + if (String(table.getCellOriginValue(2, 2)) !== '11111') + throw new Error('编辑值未提交'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/edit/start-with-value.mjs b/packages/vtable/__tests__/visual/cases/edit/start-with-value.mjs new file mode 100644 index 0000000000..8f6bb879ad --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/edit/start-with-value.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 66960d6749841700ac7664d4 + * 验证目的:输入编辑器通过 startEditCell 的初始值参数打开并显示该值。 + * 改写:编辑器从本地 bundle 加载,删除带时间戳的内网 CDN 请求。 + */ +export default { + mount(container) { + // 本地注册与来源相同的输入和日期编辑器,再用第三列第二行启动编辑。 + const VTable = window.VTable; + VTable.register.editor('input-editor', new VTable.editors.InputEditor({})); + VTable.register.editor('date-editor', new VTable.editors.DateInputEditor({})); + const table = new VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, editor: 'input-editor' }, + { field: 'birthday', title: 'Birthday', width: 150, editor: 'date-editor' }, + { field: 'id', title: 'ID', width: 100, editor: 'input-editor' }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A', birthday: '2019-01-01' }, + { progress: 80, name: 'B', birthday: '2010-11-01' }, + { progress: 1, id: 3, name: 'C', birthday: '2013-10-20' } + ], + widthMode: 'standard', allowFrozenColCount: 2 + }); + table.startEditCell(2, 2, 'nihao'); + return table; + }, + async verify(page) { + // 确认实际编辑控件已挂载,并接收 startEditCell 指定的初始值。 + await page.evaluate(() => { + const table = window.__visualTable; + const editor = table.getEditor(2, 2); + if (!editor?.element || editor.element.value !== 'nihao') + throw new Error('输入编辑器初始值不正确'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/empty/list-resize.mjs b/packages/vtable/__tests__/visual/cases/empty/list-resize.mjs new file mode 100644 index 0000000000..8829995c36 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/empty/list-resize.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 66554c5a5a5b1400ab9139e9 + * 验证目的:空记录表在容器尺寸变化后保持表头与 emptyTip 绘制。 + * 改写:减少重复列数量,保留水平溢出、冻结列与创建后缩小宿主条件。 + */ +export default { + mount(container) { + // 先以 800x600 创建,再缩至来源的 500x300 条件。 + const columns = Array.from({ length: 8 }, (_, index) => ({ field: `field${index}`, title: `Column ${index}`, width: 150 })); + const table = new window.VTable.ListTable(container, { + columns, records: [], frozenColCount: 2, widthMode: 'standard', emptyTip: {} + }); + container.style.width = '500px'; + container.style.height = '300px'; + table.resize(); + return table; + }, + async verify(page) { + // 确认空数据和缩小后的视口均真实存在,通用绘制检查负责非空画布。 + await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table'); + if (table.records.length !== 0 || host.clientWidth !== 500 || host.clientHeight !== 300) + throw new Error('空表尺寸条件未生效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/empty/pivot-tip.mjs b/packages/vtable/__tests__/visual/cases/empty/pivot-tip.mjs new file mode 100644 index 0000000000..76e68c6bfe --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/empty/pivot-tip.mjs @@ -0,0 +1,22 @@ +/** + * BugServer case IDs: 66554d175a5b1400ab9139eb + * 验证目的:无记录透视表显示空状态并保留强制角头。 + * 改写:维度名称换成通用名称,保留两级行列及双指标。 + */ +export default { + mount(container) { + // 不传 records,检验空表布局分支。 + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['kind', 'variant'], indicators: ['amount', 'count'], + enableDataAnalysis: true, indicatorsAsCol: false, + corner: { forceShowHeader: true, titleOnDimension: 'row' }, emptyTip: {}, widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 角头必须可见,表格仍有有效布局尺寸。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount < 1 || table.colCount < 1) throw new Error('空透视表未布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/drag-adjust-count.mjs b/packages/vtable/__tests__/visual/cases/frozen/drag-adjust-count.mjs new file mode 100644 index 0000000000..5d330a4c58 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/drag-adjust-count.mjs @@ -0,0 +1,41 @@ +/** + * BugServer case IDs: 65ae4667366fb000953feeb4 + * 验证目的:adjustFrozenCount 模式将普通列拖入左冻结区时增加冻结列数。 + * 改写:来源的大数据和额外图标删除,只保留跨冻结边界拖动。 + */ +export default { + mount(container) { + // 前两列冻结,列 C 从非冻结区移入冻结区后应将冻结列数改为三。 + return new window.VTable.ListTable(container, { + columns: ['A', 'B', 'C', 'D', 'E'].map(field => ({ field, title: field, width: 120 })), + records: [{ A: 'A1', B: 'B1', C: 'C1', D: 'D1', E: 'E1' }], + dragHeaderMode: 'all', frozenColDragHeaderMode: 'adjustFrozenCount', + frozenColCount: 2, widthMode: 'standard' + }); + }, + async exercise(page) { + // 在真实表头上选中 C,再拖至 A 的左侧。 + const [from, to] = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [2, 0].map(col => { + const b = table.getCellRect(col, 0).bounds; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + }); + await page.mouse.click(from.x, from.y); + await page.mouse.move(from.x, from.y); + await page.mouse.down(); + await page.mouse.move(to.x, to.y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // 顺序和冻结列数必须同步变化,避免只更新外观。 + await page.evaluate(() => { + const table = window.__visualTable; + const fields = [0, 1, 2, 3, 4].map(col => table.getHeaderField(col, 0)); + if (fields.join(',') !== 'C,A,B,D,E' || table.frozenColCount !== 3) + throw new Error(`拖入冻结区未调整列数:${JSON.stringify({ fields, count: table.frozenColCount })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/drag-disabled.mjs b/packages/vtable/__tests__/visual/cases/frozen/drag-disabled.mjs new file mode 100644 index 0000000000..1a3e0463b5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/drag-disabled.mjs @@ -0,0 +1,43 @@ +/** + * BugServer case IDs: 65ae4544366fb000953feeb1 + * 验证目的:disabled 模式禁止拖动冻结列表头,同时普通列仍可拖动。 + * 改写:来源的五千行人员记录和 SVG 去除,保留左右冻结及两次表头拖动。 + */ +export default { + mount(container) { + // 前两列和末列冻结,普通列 C、D 可作为对照进行真实拖动。 + return new window.VTable.ListTable(container, { + columns: ['A', 'B', 'C', 'D', 'E'].map(field => ({ field, title: field, width: 120 })), + records: [{ A: 'A1', B: 'B1', C: 'C1', D: 'D1', E: 'E1' }], + dragHeaderMode: 'all', frozenColDragHeaderMode: 'disabled', + frozenColCount: 2, rightFrozenColCount: 1, widthMode: 'standard' + }); + }, + async exercise(page) { + // 先尝试把冻结列 A 拖至 D,再将普通列 D 拖至 C。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [0, 2, 3].map(col => { + const b = table.getCellRect(col, 0).bounds; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + }); + for (const [from, to] of [[points[0], points[2]], [points[2], points[1]]]) { + await page.mouse.click(from.x, from.y); + await page.mouse.move(from.x, from.y); + await page.mouse.down(); + await page.mouse.move(to.x, to.y, { steps: 12 }); + await page.mouse.up(); + } + }, + async verify(page) { + // 冻结列仍在原位,普通两列交换,说明并非整个拖动模式失效。 + await page.evaluate(() => { + const table = window.__visualTable; + const fields = [0, 1, 2, 3, 4].map(col => table.getHeaderField(col, 0)); + if (fields.join(',') !== 'A,B,D,C,E' || table.frozenColCount !== 2) + throw new Error(`禁拖冻结列表头结果异常:${JSON.stringify(fields)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/one-column-left.mjs b/packages/vtable/__tests__/visual/cases/frozen/one-column-left.mjs new file mode 100644 index 0000000000..901ca11ba2 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/one-column-left.mjs @@ -0,0 +1,22 @@ +/** + * BugServer case IDs: 65adebb6af6266008c860c51 + * 验证目的:唯一一列配置为左冻结列时,表格仍能绘制记录。 + * 改写:保留单列、showPin 与 frozenColCount=1;名称改为通用值。 + */ +export default { + mount(container) { + // 单列表格不能借其他非冻结列掩盖边界问题。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }], + records: [{ id: 1 }], showPin: true, widthMode: 'standard', frozenColCount: 1 + }); + }, + async verify(page) { + // 验证唯一数据格仍可访问且原始左冻结配置仍被保留。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 1 || table.getCellValue(0, 1) !== 1 || table.options.frozenColCount !== 1) + throw new Error('单列左冻结配置或绘制失效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/one-column-right.mjs b/packages/vtable/__tests__/visual/cases/frozen/one-column-right.mjs new file mode 100644 index 0000000000..9983acd520 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/one-column-right.mjs @@ -0,0 +1,22 @@ +/** + * BugServer case IDs: 65adebf8366fb000953fee50 + * 验证目的:唯一一列同时是右冻结列时,表格仍能绘制记录。 + * 改写:保留单列、showPin 与 rightFrozenColCount=1;名称改为通用值。 + */ +export default { + mount(container) { + // 右冻结覆盖全表宽度,直接触及左右边界重合场景。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }], + records: [{ id: 1 }], showPin: true, widthMode: 'standard', rightFrozenColCount: 1 + }); + }, + async verify(page) { + // 验证右冻结数和唯一单元格都存在。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 1 || table.getCellValue(0, 1) !== 1 || table.rightFrozenColCount !== 1) + throw new Error('单列右冻结失效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/pivot-max-frozen-width.mjs b/packages/vtable/__tests__/visual/cases/frozen/pivot-max-frozen-width.mjs new file mode 100644 index 0000000000..c23a7c763e --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/pivot-max-frozen-width.mjs @@ -0,0 +1,31 @@ +/** + * BugServer case IDs: 676e6ce88e768100b114c2f0 + * 验证目的:透视表冻结行头超过 maxFrozenWidth 时逐列解冻而非全部解冻。 + * 改写:用三层匿名行维度及固定金额代替来源的大型数据表。 + */ +export default { + mount(container) { + // 三层行头的总宽超过容器一半,触发冻结宽度裁剪。 + container.style.width = '700px'; + container.style.height = '320px'; + return new window.VTable.PivotTable(container, { + rows: ['group', 'type', 'item'], columns: ['period'], indicators: ['amount'], + records: [ + { group: 'A', type: 'X', item: 'X1', period: 'First', amount: 10 }, + { group: 'A', type: 'X', item: 'X2', period: 'Second', amount: 20 }, + { group: 'B', type: 'Y', item: 'Y1', period: 'First', amount: 30 } + ], + defaultHeaderColWidth: 170, defaultColWidth: 150, + frozenColCount: 3, maxFrozenWidth: '40%', unfreezeAllOnExceedsMaxWidth: false, + widthMode: 'standard' + }); + }, + async verify(page) { + // 冻结列必须少于请求的三列且仍保留至少一列。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.frozenColCount < 1 || table.frozenColCount >= 3) + throw new Error(`冻结宽度未逐列裁剪:${table.frozenColCount}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/right-bottom.mjs b/packages/vtable/__tests__/visual/cases/frozen/right-bottom.mjs new file mode 100644 index 0000000000..77cdbd261d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/right-bottom.mjs @@ -0,0 +1,23 @@ +/** + * BugServer case IDs: 65e1837e7c3a0c00c99f2c4a + * 验证目的:左右冻结列与底部冻结行同时配置时可绘制。 + * 改写:原例的订单字段换成普通编号;保留左右冻结计数重叠的边界条件。 + */ +export default { + mount(container) { + // 两列共用字段,左冻一列、右冻两列覆盖来源边界组合。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 'auto', sort: true }, + { field: 'id', title: 'ID copy', width: 'auto', sort: true }], + records: [{ id: 'A-001' }], frozenColCount: 1, rightFrozenColCount: 2, + bottomFrozenRowCount: 1, widthMode: 'standard' + }); + }, + async verify(page) { + // 冻结交叠不应损坏唯一记录或表格尺寸。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== 'A-001' || table.colCount !== 2) throw new Error('冻结列绘制异常'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/scroll-frozen-columns.mjs b/packages/vtable/__tests__/visual/cases/frozen/scroll-frozen-columns.mjs new file mode 100644 index 0000000000..1dcb890270 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/scroll-frozen-columns.mjs @@ -0,0 +1,42 @@ +/** + * BugServer case IDs: 69c23daa709fdc006857f1c8 + * 验证目的:左右冻结区在内容宽于视口时各自接收横向滚轮。 + * 改写:来源的重复人员列改为八个匿名数值列,保留两侧冻结宽度限制。 + */ +export default { + mount(container) { + // 左右冻结内容均超过各自 180px 视口,产生独立内部滚动范围。 + container.style.width = '700px'; + container.style.height = '310px'; + return new window.VTable.ListTable(container, { + columns: Array.from({ length: 8 }, (_, index) => ({ + field: `c${index}`, title: `C${index}`, width: 120 + })), + records: Array.from({ length: 6 }, (_, row) => + Object.fromEntries(Array.from({ length: 8 }, (_, col) => [`c${col}`, `${row}-${col}`]))), + frozenColCount: 3, rightFrozenColCount: 2, + maxFrozenWidth: 180, maxRightFrozenWidth: 180, + scrollFrozenCols: true, scrollRightFrozenCols: true, + widthMode: 'standard' + }); + }, + async exercise(page) { + // 在左冻结区向右滚,在右冻结区反向滚以展开两边被裁剪的内容。 + const host = await page.locator('#table').boundingBox(); + await page.mouse.move(host.x + 80, host.y + 90); + await page.mouse.wheel(90, 0); + await page.mouse.move(host.x + host.width - 80, host.y + 90); + await page.mouse.wheel(-90, 0); + }, + async verify(page) { + // 两侧各自的滚动位置均改变,冻结列数没有被宽度上限自动削减。 + await page.evaluate(() => { + const table = window.__visualTable; + const scroll = table.stateManager.scroll; + if (table.frozenColCount !== 3 || table.rightFrozenColCount !== 2 || + table.getFrozenColsOffset() <= 0 || table.getRightFrozenColsOffset() <= 0 || + scroll.frozenHorizontalBarPos <= 0 || scroll.rightFrozenHorizontalBarPos <= 0) + throw new Error(`冻结区内部滚动未生效:${JSON.stringify(scroll)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/short-content-connected.mjs b/packages/vtable/__tests__/visual/cases/frozen/short-content-connected.mjs new file mode 100644 index 0000000000..ec8f51a061 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/short-content-connected.mjs @@ -0,0 +1,30 @@ +/** + * BugServer case IDs: 6a83c88f652957005d019ab2 + * 验证目的:短内容大容器中,左冻结列、顶部五行和底部两行冻结区相接。 + * 改写:使用通用本地记录,不保留示例邮箱,保留冻结数量与底部颜色。 + */ +export default { + mount(container) { + // 大于内容高度的容器暴露上下冻结区连接边界。 + container.style.width = '1000px'; + container.style.height = '800px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 120 }, + { field: 'name', title: 'Name', width: 180 }, { field: 'city', title: 'City', width: 180 }, + { field: 'sales', title: 'Sales', width: 180 }, { field: 'note', title: 'Note', width: 200 }], + records: Array.from({ length: 10 }, (_, i) => ({ id: i + 1, name: `Name ${i + 1}`, + city: ['A', 'B', 'C'][i % 3], sales: 1000 + i * 100, note: `Row ${i + 1}` })), + frozenColCount: 2, rightFrozenColCount: 0, frozenRowCount: 5, bottomFrozenRowCount: 2, + defaultColWidth: 150, theme: { bottomFrozenStyle: { bgColor: '#fff7cc' } } + }); + }, + async verify(page) { + // 冻结分区计数和最后一条记录必须符合源配置。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.frozenColCount !== 2 || table.frozenRowCount !== 5 || + table.bottomFrozenRowCount !== 2 || table.getCellValue(0, 10) !== 10) + throw new Error('短内容冻结区未正确建立'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/top-bottom-border.mjs b/packages/vtable/__tests__/visual/cases/frozen/top-bottom-border.mjs new file mode 100644 index 0000000000..b37a2456ad --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/top-bottom-border.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 6a83c8713335650068dcf413 + * 验证目的:顶部冻结三行、底部冻结一行时,红色外边框仍连续绘制。 + * 改写:保留冻结数量和四边框配置,使用固定编号数据。 + */ +export default { + mount(container) { + // 表体与两端冻结区同时可见,边框问题由截图比较发现。 + container.style.height = '500px'; + return new window.VTable.ListTable(container, { + columns: ['id', 'name', 'city', 'sales', 'profit'].map(field => ({ field, title: field, width: 170 })), + records: Array.from({ length: 6 }, (_, i) => ({ + id: i + 1, name: `Name ${i + 1}`, city: `City ${i + 1}`, sales: 1000 + i * 100, profit: 120 + i * 10 + })), + frozenRowCount: 3, bottomFrozenRowCount: 1, widthMode: 'standard', + theme: { frameStyle: { borderLineWidth: [1, 1, 1, 1], borderColor: 'red' } } + }); + }, + async verify(page) { + // 最后冻结行仍指向最后一条记录。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.frozenRowCount !== 3 || table.bottomFrozenRowCount !== 1 || table.getCellValue(0, 6) !== 6) + throw new Error('上下冻结行边界错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/baseline-bottom.mjs b/packages/vtable/__tests__/visual/cases/gantt/baseline-bottom.mjs new file mode 100644 index 0000000000..f3762f0fd5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/baseline-bottom.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 69a6810b2d80dd005eccdeac + * 验证目的:Gantt 任务条下方显示计划基线,三级时间轴与进度同时绘制。 + * 改写:任务文字和人员字段改为通用名称,保留实际、基线日期及样式结构。 + */ +export default { + mount(container) { + // 固定跨月日期,确保月、周、日三级刻度与基线都进入截图。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Task A', startDate: '2024-07-05', endDate: '2024-07-14', + baselineStartDate: '2024-07-01', baselineEndDate: '2024-07-10', progress: 80 }, + { id: 2, title: 'Task B', startDate: '2024-07-15', endDate: '2024-07-25', + baselineStartDate: '2024-07-11', baselineEndDate: '2024-07-20', progress: 40 }, + { id: 3, title: 'Task C', startDate: '2024-08-05', endDate: '2024-08-20', + baselineStartDate: '2024-08-01', baselineEndDate: '2024-08-15', progress: 0 } + ], + taskListTable: { columns: [ + { field: 'title', title: 'Task', width: 100 }, + { field: 'progress', title: 'Progress', width: 100, format: value => `${value}%` } + ], tableWidth: 'auto', minTableWidth: 100, maxTableWidth: 500 }, + headerRowHeight: 50, rowHeight: 90, + taskBar: { + startDateField: 'startDate', endDateField: 'endDate', progressField: 'progress', + baselineStartDateField: 'baselineStartDate', baselineEndDateField: 'baselineEndDate', + labelText: '{title}', labelTextStyle: { fontFamily: 'Arial', fontSize: 14, color: '#ffffff' }, + barStyle: { width: 25, barColor: '#3498db', completedBarColor: '#27ae60', cornerRadius: 5 }, + baselineStyle: { width: 15, barColor: 'gray', cornerRadius: 5 } + }, + timelineHeader: { backgroundColor: '#EEF1F5', colWidth: 50, scales: [ + { unit: 'month', step: 1 }, { unit: 'week', step: 1, startOfWeek: 'monday' }, { unit: 'day', step: 1 } + ] }, + minDate: '2024-06-30', maxDate: '2024-09-01', + grid: { horizontalLine: { lineWidth: 1, lineColor: '#e1e4e8' } }, overscrollBehavior: 'none' + }); + }, + async verify(page) { + // 任务表与任务条的矩形应同时有效,基线外观由截图比较。 + await page.evaluate(() => { + const gantt = window.__visualTable; + const rect = gantt.getTaskBarRelativeRect(0); + if (!rect || !(rect.width > 0) || !gantt.taskListTableInstance) + throw new Error('Gantt 任务条或任务表缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/baseline-overlap.mjs b/packages/vtable/__tests__/visual/cases/gantt/baseline-overlap.mjs new file mode 100644 index 0000000000..8eb4b7fd46 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/baseline-overlap.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 69a681c22d80dd005eccdead + * 验证目的:基线与任务条使用 overlap 布局时两层都进入绘制。 + * 改写:任务名称匿名化,保留交叠日期、进度与 overlap 配置。 + */ +export default { + mount(container) { + // 第一条基线先于任务开始,第二条基线与任务结束重叠。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [{ id: 1, title: 'Task A', startDate: '2024-07-05', endDate: '2024-07-14', + baselineStartDate: '2024-07-01', baselineEndDate: '2024-07-10', progress: 80 }, + { id: 2, title: 'Task B', startDate: '2024-07-08', endDate: '2024-07-12', + baselineStartDate: '2024-07-03', baselineEndDate: '2024-07-08', progress: 100 }], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 100 }, + { field: 'progress', title: 'Progress', width: 100 }], tableWidth: 'auto', minTableWidth: 100, maxTableWidth: 500 }, + headerRowHeight: 50, rowHeight: 90, + taskBar: { startDateField: 'startDate', endDateField: 'endDate', progressField: 'progress', + baselineStartDateField: 'baselineStartDate', baselineEndDateField: 'baselineEndDate', + baselinePosition: 'overlap', labelText: '{title}', + barStyle: { width: 25, barColor: '#3498db', completedBarColor: '#27ae60' }, + baselineStyle: { width: 15, barColor: 'gray' } }, + timelineHeader: { colWidth: 50, scales: [{ unit: 'week', step: 1, startOfWeek: 'monday' }, + { unit: 'day', step: 1 }] }, minDate: '2024-06-30', maxDate: '2024-08-01' + }); + }, + async verify(page) { + // 两条任务条的相对矩形均须可用,基线相对位置由截图比较。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records.length !== 2 || !(gantt.getTaskBarRelativeRect(0)?.width > 0) || + !(gantt.getTaskBarRelativeRect(1)?.width > 0)) throw new Error('overlap 任务条未绘制'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-function.mjs b/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-function.mjs new file mode 100644 index 0000000000..4bc35b8709 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-function.mjs @@ -0,0 +1,42 @@ +/** + * BugServer case IDs: 69a68300ec91eb005f9ad659 + * 验证目的:barStyle 与 baselineStyle 函数根据任务索引给出不同 paddingTop。 + * 改写:匿名化任务,只保留来源的索引计算与日期关系。 + */ +export default { + mount(container) { + // 两条任务触发不同的函数样式分支,使错位变化进入截图。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Task A', startDate: '2024-07-05', endDate: '2024-07-14', + baselineStartDate: '2024-07-01', baselineEndDate: '2024-07-10', progress: 80 }, + { id: 2, title: 'Task B', startDate: '2024-07-08', endDate: '2024-07-12', + baselineStartDate: '2024-07-03', baselineEndDate: '2024-07-08', progress: 100 } + ], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 100 }, + { field: 'progress', title: 'Progress', width: 100 }], + tableWidth: 'auto', minTableWidth: 100, maxTableWidth: 500 }, + headerRowHeight: 50, rowHeight: 90, + taskBar: { startDateField: 'startDate', endDateField: 'endDate', progressField: 'progress', + baselineStartDateField: 'baselineStartDate', baselineEndDateField: 'baselineEndDate', + labelText: '{title}', + // 函数配置是此来源与固定样式用例的核心差异。 + barStyle: ({ index }) => ({ paddingTop: 40 + 20 * ((index + 1) % 2), + width: 25, barColor: '#3498db', completedBarColor: '#27ae60' }), + baselineStyle: ({ index }) => ({ paddingTop: 10 + 20 * (index % 2), + width: 15, barColor: 'gray' }) }, + timelineHeader: { colWidth: 50, scales: [{ unit: 'month', step: 1 }, + { unit: 'week', step: 1, startOfWeek: 'monday' }, { unit: 'day', step: 1 }] }, + minDate: '2024-06-30', maxDate: '2024-08-01' + }); + }, + async verify(page) { + // 两条不同索引任务必须可见,具体纵向布局通过视觉截图比较。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records.length !== 2 || !(gantt.getTaskBarRelativeRect(0)?.width > 0) || + !(gantt.getTaskBarRelativeRect(1)?.width > 0)) throw new Error('函数 paddingTop 任务未绘制'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-static.mjs b/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-static.mjs new file mode 100644 index 0000000000..817bf3e1c7 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/baseline-padding-static.mjs @@ -0,0 +1,39 @@ +/** + * BugServer case IDs: 69a682bc1d0efd005e397e30 + * 验证目的:固定 paddingTop 分别移动任务条与计划基线,月周日刻度同时绘制。 + * 改写:任务和人员信息替换为通用文字,保留行高、日期与基线样式。 + */ +export default { + mount(container) { + // 两条任务覆盖不同进度,验证静态间距在同一行高下稳定绘制。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Task A', startDate: '2024-07-05', endDate: '2024-07-14', + baselineStartDate: '2024-07-01', baselineEndDate: '2024-07-10', progress: 80 }, + { id: 2, title: 'Task B', startDate: '2024-07-08', endDate: '2024-07-12', + baselineStartDate: '2024-07-03', baselineEndDate: '2024-07-08', progress: 100 } + ], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 100 }, + { field: 'progress', title: 'Progress', width: 100 }], + tableWidth: 'auto', minTableWidth: 100, maxTableWidth: 500 }, + headerRowHeight: 50, rowHeight: 90, + taskBar: { startDateField: 'startDate', endDateField: 'endDate', progressField: 'progress', + baselineStartDateField: 'baselineStartDate', baselineEndDateField: 'baselineEndDate', + labelText: '{title}', + barStyle: { paddingTop: 40, width: 25, barColor: '#3498db', completedBarColor: '#27ae60' }, + baselineStyle: { paddingTop: 10, width: 15, barColor: 'gray' } }, + timelineHeader: { colWidth: 50, scales: [{ unit: 'month', step: 1 }, + { unit: 'week', step: 1, startOfWeek: 'monday' }, { unit: 'day', step: 1 }] }, + minDate: '2024-06-30', maxDate: '2024-08-01' + }); + }, + async verify(page) { + // 两条任务必须各自形成有效的任务条矩形,间距外观由基线截图检查。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records.length !== 2 || !(gantt.getTaskBarRelativeRect(0)?.width > 0) || + !(gantt.getTaskBarRelativeRect(1)?.width > 0)) throw new Error('静态 paddingTop 任务未绘制'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/baseline-top.mjs b/packages/vtable/__tests__/visual/cases/gantt/baseline-top.mjs new file mode 100644 index 0000000000..0ddd110f50 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/baseline-top.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 69a681915bd8c7005e123d92 + * 验证目的:Gantt 任务条上方显示计划基线,三级时间轴与进度同时绘制。 + * 改写:任务文字和人员字段改为通用名称,保留实际、基线日期及样式结构。 + */ +export default { + mount(container) { + // 固定跨月日期,确保月、周、日三级刻度与基线都进入截图。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Task A', startDate: '2024-07-05', endDate: '2024-07-14', + baselineStartDate: '2024-07-01', baselineEndDate: '2024-07-10', progress: 80 }, + { id: 2, title: 'Task B', startDate: '2024-07-15', endDate: '2024-07-25', + baselineStartDate: '2024-07-11', baselineEndDate: '2024-07-20', progress: 40 }, + { id: 3, title: 'Task C', startDate: '2024-08-05', endDate: '2024-08-20', + baselineStartDate: '2024-08-01', baselineEndDate: '2024-08-15', progress: 0 } + ], + taskListTable: { columns: [ + { field: 'title', title: 'Task', width: 100 }, + { field: 'progress', title: 'Progress', width: 100, format: value => `${value}%` } + ], tableWidth: 'auto', minTableWidth: 100, maxTableWidth: 500 }, + headerRowHeight: 50, rowHeight: 90, + taskBar: { + startDateField: 'startDate', endDateField: 'endDate', progressField: 'progress', + baselineStartDateField: 'baselineStartDate', baselineEndDateField: 'baselineEndDate', + labelText: '{title}', labelTextStyle: { fontFamily: 'Arial', fontSize: 14, color: '#ffffff' }, + barStyle: { width: 25, barColor: '#3498db', completedBarColor: '#27ae60', cornerRadius: 5 }, + baselinePosition: 'top', baselineStyle: { width: 15, barColor: 'gray', cornerRadius: 5 } + }, + timelineHeader: { backgroundColor: '#EEF1F5', colWidth: 50, scales: [ + { unit: 'month', step: 1 }, { unit: 'week', step: 1, startOfWeek: 'monday' }, { unit: 'day', step: 1 } + ] }, + minDate: '2024-06-30', maxDate: '2024-09-01', + grid: { horizontalLine: { lineWidth: 1, lineColor: '#e1e4e8' } }, overscrollBehavior: 'none' + }); + }, + async verify(page) { + // 任务表与任务条的矩形应同时有效,基线外观由截图比较。 + await page.evaluate(() => { + const gantt = window.__visualTable; + const rect = gantt.getTaskBarRelativeRect(0); + if (!rect || !(rect.width > 0) || !gantt.taskListTableInstance) + throw new Error('Gantt 任务条或任务表缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/empty-mark-line.mjs b/packages/vtable/__tests__/visual/cases/gantt/empty-mark-line.mjs new file mode 100644 index 0000000000..9e7e5cb3d5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/empty-mark-line.mjs @@ -0,0 +1,28 @@ +/** + * BugServer case IDs: 68948edf2b03ab00a30d5085 + * 验证目的:无任务记录的 Gantt 仍能绘制固定日期标记线和时间轴。 + * 改写:用固定日期代替日期辅助函数,保留无 records 与 markLine 对象。 + */ +export default { + mount(container) { + // 空任务列表只保留时间轴和标记线,防止记录掩盖空状态错误。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 200 }, + { field: 'start', title: 'Start', width: 150 }, { field: 'end', title: 'End', width: 150 }], + tableWidth: 400, minTableWidth: 100, maxTableWidth: 600 }, + taskBar: { startDateField: 'start', endDateField: 'end', labelText: '{title}' }, + timelineHeader: { colWidth: 60, scales: [{ unit: 'week', step: 1, startOfWeek: 'sunday' }, + { unit: 'day', step: 1 }] }, markLine: { date: new Date('2024-08-26T00:00:00') }, + minDate: '2024-08-01', maxDate: '2024-09-30', overscrollBehavior: 'none' + }); + }, + async verify(page) { + // 无记录时仍须有任务列表实例和有效时间轴宽度。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records?.length || !gantt.taskListTableInstance || !(gantt.getXByTime(new Date('2024-08-26').getTime()) > 0)) + throw new Error('空 Gantt 标记线场景无效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/locate-offscreen-task.mjs b/packages/vtable/__tests__/visual/cases/gantt/locate-offscreen-task.mjs new file mode 100644 index 0000000000..9f51b211a0 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/locate-offscreen-task.mjs @@ -0,0 +1,62 @@ +/** + * BugServer case IDs: 69c38c89a81058005d23c094 + * 验证目的:点击时间轴左右两侧的任务定位图标,可将视口滚动到对应任务条。 + * 改写:匿名化任务名称,保留跨年时间轴、左右离屏任务及两次真实点击。 + */ +export default { + mount(container) { + // 视口先停在年中,使前后任务分别位于左右离屏区。 + container.style.height = '400px'; + const gantt = new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Task A', start: '2024-02-05', end: '2024-02-20', progress: 20 }, + { id: 2, title: 'Task B', start: '2024-03-10', end: '2024-03-18', progress: 60 }, + { id: 3, title: 'Task C', start: '2024-05-28', end: '2024-06-05', progress: 50 }, + { id: 4, title: 'Task D', start: '2024-10-05', end: '2024-10-20', progress: 40 }, + { id: 5, title: 'Task E', start: '2024-11-10', end: '2024-11-25', progress: 80 } + ], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 160 }, + { field: 'start', title: 'Start', width: 120 }], + tableWidth: 280, minTableWidth: 240, maxTableWidth: 600 }, + taskKeyField: 'id', taskBar: { startDateField: 'start', endDateField: 'end', + progressField: 'progress', locateIcon: true }, + minDate: '2024-01-01', maxDate: '2024-12-31', + timelineHeader: { colWidth: 30, scales: [{ unit: 'day', step: 1 }] }, + scrollStyle: { visible: 'scrolling' } + }); + gantt.scrollLeft = gantt.getXByTime(new Date('2024-06-01T00:00:00').getTime()); + window.__locateInitialScroll = gantt.scrollLeft; + return gantt; + }, + async exercise(page) { + // 按任务定位图标的真实场景边界点击,先向左再向右定位。 + const clickIcon = async side => { + // 每次滚动后重新寻找图标,避免使用失效的场景坐标。 + const point = await page.evaluate(side => { + const gantt = window.__visualTable; + const group = gantt.scenegraph.taskBar.locateIconsGroup; + const icon = [...(group?.children ?? [])].find(mark => + mark.name === `task-bar-locate-icon-${side}` && mark.attribute.visibleAll !== false); + if (!icon) throw new Error(`${side} 定位图标缺失`); + const bounds = icon.globalAABBBounds; + const canvas = gantt.canvas.getBoundingClientRect(); + return { x: canvas.x + (bounds.x1 + bounds.x2) / 2, + y: canvas.y + (bounds.y1 + bounds.y2) / 2 }; + }, side); + await page.mouse.click(point.x, point.y); + }; + await clickIcon('left'); + await page.waitForFunction(() => window.__visualTable.scrollLeft < window.__locateInitialScroll - 100); + await page.evaluate(() => { window.__locateLeftScroll = window.__visualTable.scrollLeft; }); + await clickIcon('right'); + await page.waitForFunction(() => window.__visualTable.scrollLeft > window.__locateLeftScroll + 100); + }, + async verify(page) { + // 两侧点击后视口必须发生双向移动,任务条数据仍保留。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records.length !== 5 || gantt.scrollLeft <= window.__locateLeftScroll) + throw new Error('离屏任务定位图标未完成双向滚动'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/move-task-bar.mjs b/packages/vtable/__tests__/visual/cases/gantt/move-task-bar.mjs new file mode 100644 index 0000000000..1236e27809 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/move-task-bar.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6a326895a44900005e2b8e22 + * 验证目的:拖动任务条后起止日期与 MOVE_END_TASK_BAR 事件同步更新。 + * 改写:任务名称匿名化,保留按天时间轴、moveable 配置及真实拖动动作。 + */ +export default { + mount(container) { + // 两个普通任务为拖动前后提供稳定的时间和位置参照。 + container.style.height = '400px'; + const gantt = new window.VTableGantt.Gantt(container, { + records: [{ id: 1, title: 'Task A', start: '2024-12-05', end: '2024-12-12', progress: 20 }, + { id: 2, title: 'Task B', start: '2024-12-10', end: '2024-12-18', progress: 35 }], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 160 }, + { field: 'start', title: 'Start', width: 120 }], tableWidth: 280 }, + taskKeyField: 'id', taskBar: { startDateField: 'start', endDateField: 'end', + progressField: 'progress', moveable: true, labelText: '{title}' }, + minDate: '2024-12-01', maxDate: '2024-12-31', + timelineHeader: { colWidth: 30, scales: [{ unit: 'day', step: 1 }] } + }); + window.__moveTaskBarEvent = null; + gantt.on('move_end_task_bar', args => { window.__moveTaskBarEvent = args; }); + return gantt; + }, + async exercise(page) { + // 从首个任务条中心向右拖动两个日期刻度。 + const point = await page.evaluate(() => { + const rect = window.__visualTable.getTaskBarRelativeRect(0); + if (!rect) throw new Error('任务条未渲染'); + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + rect.left + rect.width / 2, + y: host.y + rect.top + rect.height / 2 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.down(); + await page.mouse.move(point.x + 60, point.y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // 日期必须实质变化,且拖动完成事件引用同一条任务记录。 + await page.evaluate(() => { + const gantt = window.__visualTable; + if (gantt.records[0].start === '2024-12-05' || + window.__moveTaskBarEvent?.record?.id !== 1) + throw new Error(`任务拖动未更新:${gantt.records[0].start}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/project-range-set-records.mjs b/packages/vtable/__tests__/visual/cases/gantt/project-range-set-records.mjs new file mode 100644 index 0000000000..38cff1b924 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/project-range-set-records.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 6aaf8946952abe004538cf80 + * 验证目的:setRecords 引入项目子任务后,项目起止时间按子任务边界重算。 + * 改写:去掉截图状态标签,保留原始子任务的逆序时间边界。 + */ +export default { + mount(container) { + // 先创建普通任务,再用 setRecords 切换为无显式时间的项目。 + container.style.height = '360px'; + const gantt = new window.VTableGantt.Gantt(container, { + records: [{ id: 1, name: 'Initial task', start: '2024-11-01', end: '2024-11-02' }], + taskListTable: { columns: [{ field: 'name', title: 'Task', width: 160, tree: true }, + { field: 'start', title: 'Start', width: 110 }, { field: 'end', title: 'End', width: 110 }], tableWidth: 380 }, + tasksShowMode: window.VTableGantt.TYPES.TasksShowMode.Tasks_Separate, + taskBar: { startDateField: 'start', endDateField: 'end', labelText: '{name}' }, + timelineHeader: { colWidth: 50, scales: [{ unit: 'week', step: 1, startOfWeek: 'monday' }, + { unit: 'day', step: 1 }] }, minDate: '2024-11-01', maxDate: '2024-11-30' + }); + gantt.setRecords([{ id: 2, name: 'Project', type: 'project', children: [ + { id: 3, name: 'Design', start: '2024-11-15', end: '2024-11-18' }, + { id: 4, name: 'Review', start: '2024-11-12', end: '2024-11-20' } + ] }]); + return gantt; + }, + async verify(page) { + // 项目开始日期必须取较早子任务,结束日期必须取较晚子任务。 + await page.evaluate(() => { + const project = window.__visualTable.records[0]; + if (project.start !== '2024-11-12' || project.end !== '2024-11-20') + throw new Error(`项目时间未重算:${project.start} - ${project.end}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/taskbar-relative-rect.mjs b/packages/vtable/__tests__/visual/cases/gantt/taskbar-relative-rect.mjs new file mode 100644 index 0000000000..5f102d1520 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/taskbar-relative-rect.mjs @@ -0,0 +1,60 @@ +/** + * BugServer case IDs: 6a68596802c575005f77ab28 + * 验证目的:项目子任务内联显示时,空任务和两个子任务的相对矩形不同。 + * 改写:省略 BugServer 状态条,改由测试断言检查原有 click_cell 触发条件。 + */ +export default { + mount(container) { + // 固定时间轴和记录,保留来源用例的空行与两个分离子任务。 + container.style.height = '400px'; + const types = window.VTableGantt.TYPES; + const table = new window.VTableGantt.Gantt(container, { + records: [ + { id: 1, title: 'Project', type: types.TaskType.PROJECT, children: [ + { id: 11, title: 'Task A', start: '2024-07-01', end: '2024-07-04', progress: 30 }, + { id: 12, title: 'Task B', start: '2024-07-08', end: '2024-07-12', progress: 60 } + ] }, + { id: 2, title: 'Empty task row' } + ], + taskListTable: { columns: [ + { field: 'title', title: 'title', width: 220 }, + { field: 'start', title: 'start', width: 120 }, + { field: 'end', title: 'end', width: 120 }, + { field: 'progress', title: 'progress', width: 100 } + ], tableWidth: 260 }, + taskKeyField: 'id', + tasksShowMode: types.TasksShowMode.Project_Sub_Tasks_Inline, + taskBar: { startDateField: 'start', endDateField: 'end', progressField: 'progress' }, + minDate: '2024-07-01', maxDate: '2024-07-20', + timelineHeader: { colWidth: 36, scales: [{ unit: 'day', step: 1 }] }, + grid: { verticalLine: { lineWidth: 1, lineColor: '#e1e4e8' }, horizontalLine: { lineWidth: 1, lineColor: '#e1e4e8' } } + }); + window.__ganttClicked = false; + table.taskListTableInstance?.on('click_cell', args => { + if (args.col === 0 && args.row === 0) window.__ganttClicked = true; + }); + return table; + }, + async exercise(page) { + // 点击来源指定的左侧任务单元格,再验证事件与矩形。 + const point = await page.evaluate(() => { + const bounds = window.__visualTable.taskListTableInstance.getCellRect(0, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 空任务必须无矩形,两个子任务必须各有有限且分离的布局。 + await page.evaluate(() => { + const table = window.__visualTable; + if (!window.__ganttClicked) throw new Error('任务表点击事件未触发'); + const empty = table.getTaskBarRelativeRect(1); + const first = table.getTaskBarRelativeRect(0, [0, 0]); + const second = table.getTaskBarRelativeRect(0, [0, 1]); + const valid = rect => rect && ['left', 'top', 'width', 'height'].every(key => Number.isFinite(rect[key])); + if (empty !== null || !valid(first) || !valid(second) || first.left === second.left) + throw new Error('任务条相对矩形不符合预期'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/gantt/tree-move-resize.mjs b/packages/vtable/__tests__/visual/cases/gantt/tree-move-resize.mjs new file mode 100644 index 0000000000..7ecc0618f9 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/tree-move-resize.mjs @@ -0,0 +1,60 @@ +/** + * BugServer case IDs: 67c161acd824e100b091a557 + * 验证目的:树形任务的子任务条可移动并调整结束日期。 + * 改写:任务名及日期换成固定示例,保留展开层级、moveable 和 resizable。 + */ +export default { + mount(container) { + // 展开的父任务使子任务条对应可见行 1。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [{ id: 'group', title: 'Group', start: '2025-01-02', end: '2025-01-13', + progress: 20, hierarchyState: 'expand', children: [ + { id: 'child', title: 'Child', start: '2025-01-04', end: '2025-01-06', progress: 10 } + ] }], + taskListTable: { columns: [{ field: 'title', title: 'Task', width: 170, tree: true }, + { field: 'start', title: 'Start', width: 110 }], tableWidth: 280 }, + taskKeyField: 'id', taskBar: { startDateField: 'start', endDateField: 'end', + progressField: 'progress', moveable: true, resizable: true, labelText: '{title}' }, + minDate: '2025-01-01', maxDate: '2025-01-25', + rowHeight: 40, timelineHeader: { colWidth: 35, scales: [{ unit: 'day', step: 1 }] } + }); + }, + async exercise(page) { + // 子任务先向右移动两天,再拖动右边缘延长一天。 + const first = await page.evaluate(() => { + const rect = window.__visualTable.getTaskBarRelativeRect(1); + if (!rect) throw new Error('子任务条未渲染'); + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + rect.left + rect.width / 2, + y: host.y + rect.top + rect.height / 2 }; + }); + await page.mouse.move(first.x, first.y); + await page.mouse.down(); + await page.mouse.move(first.x + 70, first.y, { steps: 12 }); + await page.mouse.up(); + await page.evaluate(() => { + const child = window.__visualTable.records[0].children[0]; + window.__childAfterMove = { start: child.start, end: child.end }; + }); + const edge = await page.evaluate(() => { + const rect = window.__visualTable.getTaskBarRelativeRect(1); + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + rect.left + rect.width - 3, + y: host.y + rect.top + rect.height / 2 }; + }); + await page.mouse.move(edge.x, edge.y); + await page.mouse.down(); + await page.mouse.move(edge.x + 35, edge.y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // 起始日期和末日期应分别响应移动与右缘拉伸。 + await page.evaluate(() => { + const child = window.__visualTable.records[0].children[0]; + if (window.__childAfterMove.start === '2025-01-04' || + child.end === window.__childAfterMove.end) + throw new Error(`树形任务移动或拉伸未生效:${JSON.stringify(child)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/group/add-delete-records.mjs b/packages/vtable/__tests__/visual/cases/group/add-delete-records.mjs new file mode 100644 index 0000000000..70c488e851 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/group/add-delete-records.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 6787a95e54366a00b133b77a, 6787ae11863ad000b1fc4081 + * 验证目的:两级 groupBy 中按树路径插入和删除记录时分组行保持一致。 + * 改写:去除订单、客户及地址字段,使用固定 A/B 分类和短编号。 + */ +export default { + mount(container) { + // 相同二级分组有两条记录,供路径插入和删除验证。 + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'label', title: 'Item', width: 180 }, + { field: 'value', title: 'Value', width: 120 }], + records: [ + { category: 'A', sub: 'X', label: 'Item 1', value: 10 }, + { category: 'A', sub: 'X', label: 'Item 2', value: 20 }, + { category: 'B', sub: 'Y', label: 'Item 3', value: 30 } + ], + groupBy: ['category', 'sub'], hierarchyExpandLevel: 2, + rowSeriesNumber: { title: 'No.', dragOrder: true } + }); + }, + async exercise(page) { + // 与来源一致,先在首个子分组位置插入,再删除该分组的第二条记录。 + await page.evaluate(() => { + const table = window.__visualTable; + window.__groupOriginal = JSON.stringify(table.records); + table.addRecords([{ category: 'A', sub: 'X', label: 'Added', value: 99 }], [0, 0, 0]); + window.__groupAfterAdd = JSON.stringify(table.records); + table.deleteRecords([[0, 0, 1]]); + window.__groupAfterDelete = JSON.stringify(table.records); + }); + }, + async verify(page) { + // 新增与删除均须改变二级分组内的记录顺序和数量。 + await page.evaluate(() => { + const before = JSON.parse(window.__groupOriginal)[0].children[0].children; + const afterAdd = JSON.parse(window.__groupAfterAdd)[0].children[0].children; + const afterDelete = JSON.parse(window.__groupAfterDelete)[0].children[0].children; + if (before.length !== 2 || afterAdd.length !== 3 || afterDelete.length !== 2 || + afterAdd[0].label !== 'Added' || afterDelete[0].label !== 'Added' || + afterDelete.some(record => record.label === 'Item 1')) + throw new Error(`分组增删顺序异常:${JSON.stringify({ before, afterAdd, afterDelete })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/group/one-column.mjs b/packages/vtable/__tests__/visual/cases/group/one-column.mjs new file mode 100644 index 0000000000..2fe0355be5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/group/one-column.mjs @@ -0,0 +1,25 @@ +/** + * BugServer case IDs: 69ae7bce709fdc006857f1c7 + * 验证目的:只显示一列时按隐藏字段分组,底部冻结行与主题仍正确布局。 + * 改写:移除外部 Olympic 数据请求,用同结构的固定通用记录触发分组。 + */ +export default { + mount(container) { + // country 不作为可见列,仅用于形成两个分组。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'athlete', title: 'Athlete', width: 120 }], + records: [{ country: 'A', athlete: 'Member 1' }, { country: 'A', athlete: 'Member 2' }, + { country: 'B', athlete: 'Member 3' }], + groupBy: 'country', bottomFrozenRowCount: 1, + autoWrapText: true, heightMode: 'autoHeight', widthMode: 'autoWidth', + theme: window.VTable.themes.ARCO.extends({ bottomFrozenStyle: { fontFamily: 'Arial', fontWeight: 500 } }) + }); + }, + async verify(page) { + // 分组增加标题行;表格仍只能有一列。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 1 || table.rowCount <= 4) throw new Error('单列分组未展开'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/grid-tree-filter-expand.mjs b/packages/vtable/__tests__/visual/cases/header/grid-tree-filter-expand.mjs new file mode 100644 index 0000000000..0716676f01 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/grid-tree-filter-expand.mjs @@ -0,0 +1,62 @@ +/** + * BugServer case IDs: 694cee0bd8a329005c45bca3 + * 验证目的:FilterPlugin 与 headerExpandLevel 共存时,分组表头图标点击可展开下级列。 + * 改写:保留三级列、空 ID、插件与真实点击动作,字段值换成通用编号。 + */ +export default { + mount(container) { + // 第二级默认展开,最深两列需要点击折叠图标后才进入表格。 + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', columns: [ + { field: 'name1', title: 'Name 1', width: 120 }, + { field: 'name2', title: 'Name 2', width: 150, columns: [ + { field: 'name21', title: 'Name 2.1', width: 150 }, + { field: 'name22', title: 'Name 2.2', width: 150 } + ] } + ] } + ], + records: Array.from({ length: 5 }, (_, index) => ({ id: index === 1 ? undefined : index + 1, + name: `Group ${index + 1}`, name1: `A${index + 1}`, name2: `B${index + 1}`, + name21: `C${index + 1}`, name22: `D${index + 1}` })), + headerHierarchyType: 'grid-tree', headerExpandLevel: 2, + widthMode: 'standard', defaultRowHeight: 40, + plugins: [new window.VTable.plugins.FilterPlugin({})] + }); + window.__headerColsBefore = table.colCount; + return table; + }, + async exercise(page) { + // 按场景图标边界点击真实表头折叠图标,覆盖录制的“展开表头”动作。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + for (let row = 0; row < Math.min(table.rowCount, 3); row++) { + for (let col = 0; col < table.colCount; col++) { + const stack = [table.scenegraph.getCell(col, row)]; + while (stack.length) { + const mark = stack.pop(); + if (mark?.attribute?.funcType === 'collapse') { + const bounds = mark.globalAABBBounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, + y: host.y + (bounds.y1 + bounds.y2) / 2 }; + } + stack.push(...(mark?.children ?? [])); + } + } + } + throw new Error('可展开表头图标缺失'); + }); + await page.mouse.click(point.x, point.y); + await page.waitForFunction(() => window.__visualTable.colCount > window.__headerColsBefore); + }, + async verify(page) { + // 实际列数必须增加,且 FilterPlugin 仍保留在表格插件中。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount <= window.__headerColsBefore || table.options.headerExpandLevel !== 2) + throw new Error(`分组表头未展开:${window.__headerColsBefore} -> ${table.colCount}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/grid-tree-transpose.mjs b/packages/vtable/__tests__/visual/cases/header/grid-tree-transpose.mjs new file mode 100644 index 0000000000..63de07fbed --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/grid-tree-transpose.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 67f3395770dedf00a7f03228 + * 验证目的:grid-tree 分组表头与 transpose 同时启用时保持层级。 + * 改写:个人信息改为通用字段,保留转置、层级、默认表头宽度与拖动配置。 + */ +export default { + mount(container) { + // 与非转置版本使用相同的分组列,单独覆盖转置布局。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'code', title: 'Code', width: 120 }, + { title: 'Group', field: 'group', columns: [ + { field: 'first', title: 'First', width: 120 }, + { field: 'last', title: 'Last', width: 120 }] }, + { field: 'city', title: 'City', width: 120 }], + records: Array.from({ length: 10 }, (_, i) => ({ id: i + 1, code: `C${i + 1}`, + first: `First ${i + 1}`, last: `Last ${i + 1}`, city: 'City' })), + defaultHeaderColWidth: 130, headerHierarchyType: 'grid-tree', transpose: true, + widthMode: 'standard', dragHeaderMode: 'all', limitMinWidth: 20, + theme: window.VTable.themes.DEFAULT.extends({ headerStyle: { color: 'red', + frameStyle: { borderColor: 'red', borderLineWidth: 2 } } }) + }); + }, + async verify(page) { + // 转置配置必须生效并生成可读数据区。 + await page.evaluate(() => { + const table = window.__visualTable; + if (!table.options.transpose || table.options.headerHierarchyType !== 'grid-tree' || + table.colCount < 10 || table.rowCount < 4) + throw new Error('转置 grid-tree 表头未正确建立'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/grid-tree.mjs b/packages/vtable/__tests__/visual/cases/header/grid-tree.mjs new file mode 100644 index 0000000000..4d86f9edb2 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/grid-tree.mjs @@ -0,0 +1,32 @@ +/** + * BugServer case IDs: 67f33ab520aeff00a653bc6c + * 验证目的:普通列表中的 grid-tree 分组表头正常排列。 + * 改写:个人姓名、电话和邮箱改为通用字段,保留分组列和层级配置。 + */ +export default { + mount(container) { + // 顶层列与双子列并列,启用可拖动的 grid-tree 表头。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'code', title: 'Code', width: 120 }, + { title: 'Group', field: 'group', columns: [ + { field: 'first', title: 'First', width: 120 }, + { field: 'last', title: 'Last', width: 120 }] }, + { field: 'city', title: 'City', width: 120 }], + records: Array.from({ length: 10 }, (_, i) => ({ id: i + 1, code: `C${i + 1}`, + first: `First ${i + 1}`, last: `Last ${i + 1}`, city: 'City' })), + defaultColWidth: 120, headerHierarchyType: 'grid-tree', widthMode: 'standard', + dragHeaderMode: 'all', limitMinWidth: 20, + theme: window.VTable.themes.DEFAULT.extends({ headerStyle: { color: 'red', + frameStyle: { borderColor: 'red', borderLineWidth: 2 } } }) + }); + }, + async verify(page) { + // grid-tree 将分组子列折叠为一列,并保留全部记录。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.options.headerHierarchyType !== 'grid-tree' || table.colCount !== 4 || table.rowCount < 11) + throw new Error(`grid-tree 分组表头未正确建立: ${JSON.stringify({ type: table.options.headerHierarchyType, cols: table.colCount, rows: table.rowCount })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/hidden-nested.mjs b/packages/vtable/__tests__/visual/cases/header/hidden-nested.mjs new file mode 100644 index 0000000000..905bab2f07 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/hidden-nested.mjs @@ -0,0 +1,28 @@ +/** + * BugServer case IDs: 677398b4d2dacd00b3443e9d + * 验证目的:三级分组表头的末级列全部隐藏后,其余表头与数据仍可见。 + * 改写:缩减重复记录,保留两级嵌套和两个 hide 末级列。 + */ +export default { + mount(container) { + // 同一分组下保留可见列与全隐藏子分组。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, { title: 'Name', columns: [ + { field: 'first', title: 'First', width: 100 }, { title: 'Hidden group', columns: [ + { field: 'second', title: 'Second', width: 100, hide: true }, + { field: 'third', title: 'Third', width: 150, hide: true } + ] } + ] }], + records: [{ id: 1, first: 'A', second: 'B', third: 'C' }, { id: 2, first: 'D', second: 'E', third: 'F' }], + widthMode: 'standard', autoWrapText: true, autoRowHeight: true, defaultColWidth: 150 + }); + }, + async verify(page) { + // 只剩 ID 与 First 两个可见末级列。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 2 || !String(table.getCellValue(1, table.columnHeaderLevelCount)).includes('A')) + throw new Error('嵌套隐藏表头未生效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/hidden-parent.mjs b/packages/vtable/__tests__/visual/cases/header/hidden-parent.mjs new file mode 100644 index 0000000000..b3cdf0d85d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/hidden-parent.mjs @@ -0,0 +1,25 @@ +/** + * BugServer case IDs: 68998fa58af47900b375bcd4 + * 验证目的:隐藏三级分组的父节点后,同字段的独立列仍可见。 + * 改写:保留父节点 hide、重复 name2 字段和三层嵌套,缩短记录。 + */ +export default { + mount(container) { + // 隐藏整棵分组树,独立列复用被隐藏分组中的字段。 + return new window.VTable.ListTable(container, { + columns: [{ title: 'Name', hide: true, columns: [{ title: 'name-level-2', columns: [ + { field: 'name2', title: 'name2', width: 100 }, { field: 'name3', title: 'name3', width: 150 } + ] }] }, { field: 'name2', title: 'name2', width: 100 }], + records: [{ name2: 'a2', name3: 'a3' }, { name2: 'b2', name3: 'b3' }], + widthMode: 'standard', autoWrapText: true, autoRowHeight: true + }); + }, + async verify(page) { + // 隐藏父组后只显示独立 name2 列。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 1 || table.getCellValue(0, table.columnHeaderLevelCount) !== 'a2') + throw new Error('隐藏父表头后独立列未保留'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/level-span.mjs b/packages/vtable/__tests__/visual/cases/header/level-span.mjs new file mode 100644 index 0000000000..5455226878 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/level-span.mjs @@ -0,0 +1,31 @@ +/** + * BugServer case IDs: 684656c47c20ee00b3e9c578 + * 验证目的:多层列表表头中的 levelSpan 跨层占位与叶列数据正常渲染。 + * 改写:缩短通用学科文字,保留四层树和两个不同的 levelSpan 值。 + */ +export default { + mount(container) { + // 保留来源的四层表头及中间节点跨层设置。 + return new window.VTable.ListTable(container, { + columns: [ + { title: 'Object', columns: [{ title: 'Field 1', columns: [ + { title: 'F11', columns: [{ field: 'math', title: 'Math', width: 150 }] }, + { title: 'F12', levelSpan: 3, columns: [{ field: 'chinese', title: 'Language', width: 150 }] }, + { title: 'F13', columns: [{ field: 'english', title: 'English', width: 150 }] } + ] }] }, + { title: 'Basic', levelSpan: 2, columns: [{ title: 'F21', columns: [{ field: 'computer', title: 'Computer', width: 150 }] }] } + ], + records: [{ math: 'math', chinese: 'language', english: 'english', computer: 'computer' }], + widthMode: 'auto', heightMode: 'autoHeight', defaultColWidth: 120, defaultRowHeight: 40, + autoWrapText: true, theme: window.VTable.themes.DEFAULT + }); + }, + async verify(page) { + // 检查四层表头与叶列数据同时存在。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.columnHeaderLevelCount < 4 || table.colCount !== 4) throw new Error('层级表头未展开'); + if (table.getCellValue(0, table.columnHeaderLevelCount) !== 'math') throw new Error('叶列数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/merge-cells.mjs b/packages/vtable/__tests__/visual/cases/header/merge-cells.mjs new file mode 100644 index 0000000000..584371d5fa --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/merge-cells.mjs @@ -0,0 +1,32 @@ +/** + * BugServer case IDs: 64745b3b5d221c008666ee22 + * 验证目的:格式化字段和值相同的相邻记录按列合并,并保持样式回调。 + * 改写:仅保留可触发合并的记录,保留 mergeCell 和动态样式设置。 + */ +export default { + mount(container) { + // 相邻两条 A 记录触发名称列合并,ID 格式化触发另一列合并。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'id', title: 'ID', width: 100, mergeCell: true, + fieldFormat: record => record.id === 2 ? 3 : record.id }, + { field: 'name', title: 'Name', width: 150, mergeCell: true, + style: { color: args => args.row === 1 ? 'blue' : 'red', + fontSize: args => args.row === 1 ? 16 : 20 } } + ], + records: [{ id: 2, name: 'A' }, { id: 3, name: 'A' }, { id: 4, name: 'B' }], + widthMode: 'standard' + }); + }, + async verify(page) { + // 相邻两格应返回同一合并范围,第三格保持独立。 + await page.evaluate(() => { + const table = window.__visualTable; + const first = table.getCellRange(1, 1); + const second = table.getCellRange(1, 2); + const third = table.getCellRange(1, 3); + if (first.start.row !== 1 || first.end.row !== 2 || second.end.row !== 2 || third.start.row !== 3) + throw new Error('单元格合并范围错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/row-series-number.mjs b/packages/vtable/__tests__/visual/cases/header/row-series-number.mjs new file mode 100644 index 0000000000..5d42574ccd --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/row-series-number.mjs @@ -0,0 +1,24 @@ +/** + * BugServer case IDs: 66c56702c3ab4200c6b4fe01 + * 验证目的:仅开启行序号列时仍能渲染并显示连续序号。 + * 改写:原例中的人物记录替换为固定通用记录,保留序号拖动配置。 + */ +export default { + mount(container) { + // 不配置普通数据列,保留来源的只有行序号列这一边界。 + return new window.VTable.ListTable(container, { + records: [{ name: 'A' }, { name: 'B' }, { name: 'C' }], + dragHeaderMode: 'column', + rowSeriesNumber: { enable: true, title: 'No.', field: 'name', dragOrder: true, style: { color: 'red' } } + }); + }, + async verify(page) { + // 序号列必须有实际数据单元格和有效布局。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount < 1 || table.rowCount < 4) throw new Error('序号列未创建'); + const range = table.getCellRect(0, 1)?.bounds; + if (!range || range.x2 <= range.x1) throw new Error('序号列未布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/header/sort-icon-hidden.mjs b/packages/vtable/__tests__/visual/cases/header/sort-icon-hidden.mjs new file mode 100644 index 0000000000..3362cf18ee --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/header/sort-icon-hidden.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 65c0882697cc3d008de5b483 + * 验证目的:列允许排序但 showSort=false 时,初始降序数据保持可读且排序图标隐藏。 + * 改写:保留 sort 与 showSort 的冲突组合,去掉重复的说明列。 + */ +export default { + mount(container) { + // 排序能力和图标可见性分别配置,视觉断言依赖截图。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, sort: true, showSort: false }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150, sort: true }], widthMode: 'standard' + }); + table.setRecords([{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' }], { field: 'progress', order: 'desc' }); + return table; + }, + async verify(page) { + // 数据确实按 progress 降序,而图标是否隐藏由稳定截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== 100 || table.getCellValue(0, 3) !== 1) + throw new Error('隐藏排序图标场景排序失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs new file mode 100644 index 0000000000..1acc16a663 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -0,0 +1,165 @@ +/** 唯一可执行清单;bundles 指定每例需要的本地构建产物。 */ +export const cases = [ + { id: 'list-basic', purpose: '列表表头、固定数据与单元格绘制', file: './table/list-basic.mjs', bundles: ['vtable'] }, + { id: 'list-select-cell', purpose: '点击单元格后选择范围确实改变', file: './table/list-select-cell.mjs', bundles: ['vtable'] }, + { id: 'pivot-analysis-two-level', purpose: '两级维度与双指标透视数据分析', file: './pivot/analysis-two-level.mjs', bundles: ['vtable'] }, + { id: 'gantt-taskbar-relative-rect', purpose: '项目子任务与空任务的相对矩形', file: './gantt/taskbar-relative-rect.mjs', bundles: ['gantt'] }, + { id: 'sheet-add-columns', purpose: 'Sheet 公式与列插入', file: './sheet/add-columns.mjs', bundles: ['sheet'] }, + { id: 'wrapped-text', purpose: '格式化文本自动换行与显式换行', file: './cells/wrapped-text.mjs', bundles: ['vtable'] }, + { id: 'checkbox-states', purpose: '复选框状态组合', file: './cells/checkbox-states.mjs', bundles: ['vtable'] }, + { id: 'mixed-sparkline-progress', purpose: '动态单元格类型与负值进度条', file: './cells/mixed-sparkline-progress.mjs', bundles: ['vtable'] }, + { id: 'switch-button', purpose: '开关和按钮普通与禁用状态', file: './cells/switch-button.mjs', bundles: ['vtable'] }, + { id: 'level-span', purpose: '多层表头 levelSpan', file: './header/level-span.mjs', bundles: ['vtable'] }, + { id: 'initial-desc', purpose: '自定义比较器与初始降序', file: './sort/initial-desc.mjs', bundles: ['vtable'] }, + { id: 'theme-arco', purpose: 'ARCO 主题与自动行高', file: './theme/arco.mjs', bundles: ['vtable'] }, + { id: 'auto-width-height', purpose: '列宽与行高自动测量', file: './layout/auto-width-height.mjs', bundles: ['vtable'] }, + { id: 'merge-cells', purpose: '相邻单元格合并与动态样式', file: './header/merge-cells.mjs', bundles: ['vtable'] }, + { id: 'plugin-filter-hide-reorder', purpose: '筛选插件与隐藏及移动列', file: './plugins/filter-hide-reorder.mjs', bundles: ['plugins'] }, + { id: 'pivot-chart-box-plot', purpose: '透视箱线图和离群点', file: './pivot-chart/box-plot.mjs', bundles: ['vchart'] }, + { id: 'row-series-number', purpose: '独立行序号列', file: './header/row-series-number.mjs', bundles: ['vtable'] }, + { id: 'scroll-bar-to-side', purpose: '滚动条贴边与多层表头', file: './scroll/bar-to-side.mjs', bundles: ['vtable'] }, + { id: 'gantt-baseline-bottom', purpose: 'Gantt 基线与三级时间轴', file: './gantt/baseline-bottom.mjs', bundles: ['gantt'] }, + { id: 'select-cross', purpose: 'cross 模式表体与表头连续选择', file: './interaction/select-cross.mjs', bundles: ['vtable'] }, + { id: 'list-empty-resize', purpose: '空表在缩小视口中绘制', file: './empty/list-resize.mjs', bundles: ['vtable'] }, + { id: 'edit-start-with-value', purpose: '输入编辑器启动初始值', file: './edit/start-with-value.mjs', bundles: ['editors'] }, + { id: 'pivot-corner-without-rows', purpose: '无行无指标的强制角头', file: './pivot/corner-without-rows.mjs', bundles: ['vtable'] }, + { id: 'aggregation-pagination', purpose: '合并、SUM 聚合与分页', file: './analysis/aggregation-pagination.mjs', bundles: ['vtable'] }, + { id: 'update-merged-records', purpose: '合并分组中的记录更新', file: './records/update-merged.mjs', bundles: ['vtable'] }, + { id: 'transpose-theme-header', purpose: '转置分组表头与扩展主题', file: './transpose/theme-header.mjs', bundles: ['vtable'] }, + { id: 'progress-custom-layout', purpose: '动态图标、进度条与自定义布局', file: './custom/progress-layout.mjs', bundles: ['vtable'] }, + { id: 'component-title', purpose: '标题、副标题和表头点击', file: './components/title.mjs', bundles: ['vtable'] }, + { id: 'aggregation-float', purpose: '浮点 AVG 与顶部 SUM 聚合', file: './analysis/aggregation-float.mjs', bundles: ['vtable'] }, + { id: 'filter-api', purpose: '字段与函数过滤器交集', file: './analysis/filter-api.mjs', bundles: ['vtable'] }, + { id: 'frozen-right-bottom', purpose: '左右与底部冻结边界组合', file: './frozen/right-bottom.mjs', bundles: ['vtable'] }, + { id: 'pivot-empty-tip', purpose: '无数据透视表空状态', file: './empty/pivot-tip.mjs', bundles: ['vtable'] }, + { id: 'cyrillic-wrap', purpose: '西里尔字母与混合文本换行', file: './language/cyrillic-wrap.mjs', bundles: ['vtable'] }, + { id: 'adaptive-width', purpose: 'adaptive 列宽填充', file: './layout/adaptive-width.mjs', bundles: ['vtable'] }, + { id: 'pivot-virtual-column-total', purpose: '虚拟列节点与行列合计', file: './pivot/virtual-column-total.mjs', bundles: ['vtable'] }, + { id: 'sheet-formula-edit', purpose: 'Sheet 多区域公式与编辑', file: './sheet/formula-edit.mjs', bundles: ['sheet'] }, + { id: 'gantt-baseline-top', purpose: 'Gantt 任务条上方基线', file: './gantt/baseline-top.mjs', bundles: ['gantt'] }, + { id: 'tree-list-merge-expand', purpose: '树形列表与合并列展开', file: './tree/list-merge-expand.mjs', bundles: ['vtable'] }, + { id: 'sort-update-state', purpose: 'setRecords 后切换排序状态', file: './sort/update-state.mjs', bundles: ['vtable'] }, + { id: 'records-add-merged', purpose: '合并分组插入记录', file: './records/add-merged.mjs', bundles: ['vtable'] }, + { id: 'records-delete-merged', purpose: '合并分组删除记录', file: './records/delete-merged.mjs', bundles: ['vtable'] }, + { id: 'nested-field', purpose: '数组字段路径与缺失值', file: './data/nested-field.mjs', bundles: ['vtable'] }, + { id: 'promise-source', purpose: '异步 CachedDataSource 批次加载', file: './data/promise-source.mjs', bundles: ['vtable'] }, + { id: 'plugin-highlight-header', purpose: '透视表选择后的行列表头高亮', file: './plugins/highlight-header.mjs', bundles: ['plugins'] }, + { id: 'pivot-update-filter', purpose: '透视表过滤规则更新', file: './pivot/update-filter.mjs', bundles: ['vtable'] }, + { id: 'inline-image', purpose: '图片单元格边缘点击与自动尺寸', file: './cells/inline-image.mjs', bundles: ['vtable'] }, + { id: 'hover-tooltip', purpose: '多单元格悬停提示更新', file: './components/hover-tooltip.mjs', bundles: ['vtable'] }, + { id: 'menu-disabled-item', purpose: '下拉子菜单禁用项', file: './menu/disabled-item.mjs', bundles: ['vtable'] }, + { id: 'pivot-indicator-sort-rule', purpose: '透视指标排序规则和背景映射', file: './pivot/indicator-sort-rule.mjs', bundles: ['vtable'] }, + { id: 'key-size-config', purpose: '稳定 key 的列宽行高配置', file: './layout/key-size-config.mjs', bundles: ['vtable'] }, + { id: 'style-dashed-border', purpose: '虚线双色单元格边框', file: './style/dashed-border.mjs', bundles: ['vtable'] }, + { id: 'group-one-column', purpose: '隐藏分组字段的单列列表', file: './group/one-column.mjs', bundles: ['vtable'] }, + { id: 'api-update-columns', purpose: '悬停时更新列', file: './api/update-columns.mjs', bundles: ['vtable'] }, + { id: 'pivot-wide-scrollbar', purpose: '透视表宽滚动条与主题条纹', file: './scroll/pivot-wide-rail.mjs', bundles: ['vtable'] }, + { id: 'edit-complete-input', purpose: '输入编辑器完成提交', file: './edit/complete-input.mjs', bundles: ['editors'] }, + { id: 'select-disabled-column-range', purpose: '拖选不能覆盖禁选列', file: './interaction/disabled-column-range.mjs', bundles: ['vtable'] }, + { id: 'sheet-add-rows', purpose: 'Sheet 行高调整与插入记录', file: './sheet/add-rows.mjs', bundles: ['sheet'] }, + { id: 'pivot-no-indicators', purpose: '无指标透视表与链接型维度表头', file: './pivot/no-indicators.mjs', bundles: ['vtable'] }, + { id: 'keyboard-select-all-body', purpose: '快捷键全选表体且排除表头', file: './keyboard/select-all-body.mjs', bundles: ['vtable'] }, + { id: 'pivot-tree-zero-expand', purpose: '数字零值透视树节点展开', file: './pivot/tree-zero-expand.mjs', bundles: ['vtable'] }, + { id: 'plugin-master-detail-auto-height', purpose: '主从表自动高度与滚动', file: './plugins/master-detail-auto-height.mjs', bundles: ['plugins'] }, + { id: 'frozen-one-column-left', purpose: '唯一列左冻结边界', file: './frozen/one-column-left.mjs', bundles: ['vtable'] }, + { id: 'frozen-one-column-right', purpose: '唯一列右冻结边界', file: './frozen/one-column-right.mjs', bundles: ['vtable'] }, + { id: 'frozen-top-bottom-border', purpose: '上下冻结行与四边框', file: './frozen/top-bottom-border.mjs', bundles: ['vtable'] }, + { id: 'header-hidden-nested', purpose: '三级分组表头末级列隐藏', file: './header/hidden-nested.mjs', bundles: ['vtable'] }, + { id: 'style-border-clip-direction', purpose: '单元格边框裁剪方向', file: './style/border-clip-direction.mjs', bundles: ['vtable'] }, + { id: 'records-delete-all-bottom-frozen', purpose: '删除全部记录后底部冻结区重置', file: './records/delete-all-bottom-frozen.mjs', bundles: ['vtable'] }, + { id: 'records-array-path-add', purpose: '数组记录字段路径与插入', file: './records/array-path-add.mjs', bundles: ['vtable'] }, + { id: 'layout-container-fit-height', purpose: 'autoWidth 与容器高度适配', file: './layout/container-fit-height.mjs', bundles: ['vtable'] }, + { id: 'pivot-calculated-field-hidden-dependencies', purpose: '未显示依赖指标的计算字段', file: './pivot/calculated-field-hidden-dependencies.mjs', bundles: ['vtable'] }, + { id: 'gantt-project-range-set-records', purpose: 'setRecords 项目时间边界重算', file: './gantt/project-range-set-records.mjs', bundles: ['gantt'] }, + { id: 'gantt-empty-mark-line', purpose: '无任务的固定日期标记线', file: './gantt/empty-mark-line.mjs', bundles: ['gantt'] }, + { id: 'gantt-baseline-overlap', purpose: '基线与任务条重叠布局', file: './gantt/baseline-overlap.mjs', bundles: ['gantt'] }, + { id: 'pivot-chart-heatmap-two-indicators', purpose: '双热力图数据流和颜色图例', file: './pivot-chart/heatmap-two-indicators.mjs', bundles: ['vchart'] }, + { id: 'sheet-update-option', purpose: 'Sheet 全量配置更新', file: './sheet/update-option.mjs', bundles: ['sheet'] }, + { id: 'pivot-chart-box-plot-horizontal', purpose: '水平箱线图与离群点', file: './pivot-chart/box-plot-horizontal.mjs', bundles: ['vchart'] }, + { id: 'pivot-chart-histogram-overlap', purpose: '重叠区间透视直方图', file: './pivot-chart/histogram-overlap.mjs', bundles: ['vchart'] }, + { id: 'theme-dark-icons', purpose: '深色主题的冻结与排序图标', file: './theme/dark-icons.mjs', bundles: ['vtable'] }, + { id: 'plugin-fill-handle-hit-area', purpose: '填充柄视觉大小和命中范围', file: './plugins/fill-handle-hit-area.mjs', bundles: ['vtable'] }, + { id: 'pivot-update-option-row-header-width', purpose: '透视配置更新后行头列宽', file: './pivot/update-option-row-header-width.mjs', bundles: ['vtable'] }, + { id: 'pivot-custom-merge-subtotal', purpose: '行头自定义合并和小计', file: './pivot/custom-merge-subtotal.mjs', bundles: ['vtable'] }, + { id: 'sheet-copy-paste', purpose: 'Sheet 公式结果事件复制粘贴', file: './sheet/copy-paste.mjs', bundles: ['sheet'] }, + { id: 'keyboard-copy-paste-event', purpose: '列表单格事件复制粘贴', file: './keyboard/copy-paste-event.mjs', bundles: ['vtable'] }, + { id: 'sort-multiple-header-click', purpose: '多字段排序图标连续点击', file: './sort/multiple-header-click.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-scatter-axes', purpose: 'bar 与 scatter 独立轴', file: './pivot-chart/scatter-axes.mjs', bundles: ['vchart'] }, + { id: 'theme-update-theme', purpose: 'ARCO 主题运行时更新', file: './theme/update-theme.mjs', bundles: ['vtable'] }, + { id: 'header-sort-icon-hidden', purpose: '可排序列隐藏排序图标', file: './header/sort-icon-hidden.mjs', bundles: ['vtable'] }, + { id: 'plugin-context-menu-click', purpose: '上下文菜单冻结事件', file: './plugins/context-menu-click.mjs', bundles: ['plugins'] }, + { id: 'layout-container-fit-both', purpose: 'autoWidth 与布尔容器适配', file: './layout/container-fit-both.mjs', bundles: ['vtable'] }, + { id: 'header-hidden-parent', purpose: '隐藏父表头保留独立同字段列', file: './header/hidden-parent.mjs', bundles: ['vtable'] }, + { id: 'style-underline', purpose: '下划线变体与虚线边框', file: './style/underline.mjs', bundles: ['vtable'] }, + { id: 'transpose-update-option-off', purpose: '转置记录更新后关闭转置', file: './transpose/update-option-off.mjs', bundles: ['vtable'] }, + { id: 'records-add-sorted', purpose: '排序状态下批量插入缺字段记录', file: './records/add-sorted.mjs', bundles: ['vtable'] }, + { id: 'records-delete-sorted', purpose: '排序状态下双索引删除记录', file: './records/delete-sorted.mjs', bundles: ['vtable'] }, + { id: 'component-legend-resize', purpose: '单行图例和标题随容器缩窄', file: './components/legend-resize.mjs', bundles: ['vtable'] }, + { id: 'frozen-short-content-connected', purpose: '短内容上下冻结区连接边界', file: './frozen/short-content-connected.mjs', bundles: ['vtable'] }, + { id: 'tree-checkbox-set-state', purpose: '树节点复选状态设置且不级联', file: './tree/checkbox-set-state.mjs', bundles: ['vtable'] }, + { id: 'pivot-indicator-sort-subtotal', purpose: '指标路径排序与行维度小计', file: './pivot/indicator-sort-subtotal.mjs', bundles: ['vtable'] }, + { id: 'pivot-aggregation-rules', purpose: 'SUM COUNT AVG 三类聚合指标', file: './pivot/aggregation-rules.mjs', bundles: ['vtable'] }, + { id: 'header-grid-tree', purpose: '普通列表 grid-tree 分组表头', file: './header/grid-tree.mjs', bundles: ['vtable'] }, + { id: 'header-grid-tree-transpose', purpose: '转置 grid-tree 分组表头', file: './header/grid-tree-transpose.mjs', bundles: ['vtable'] }, + { id: 'menu-dropdown-highlight', purpose: '列下拉菜单状态图标与高亮', file: './menu/dropdown-highlight.mjs', bundles: ['vtable'] }, + { id: 'gantt-baseline-padding-static', purpose: 'Gantt 任务条和基线的固定纵向间距', file: './gantt/baseline-padding-static.mjs', bundles: ['gantt'] }, + { id: 'gantt-baseline-padding-function', purpose: 'Gantt 任务索引驱动的动态基线间距', file: './gantt/baseline-padding-function.mjs', bundles: ['gantt'] }, + { id: 'pivot-chart-mark-line', purpose: '柱状图汇总标记线与端点符号', file: './pivot-chart/mark-line.mjs', bundles: ['vchart'] }, + { id: 'pivot-chart-combination-forecast', purpose: '双指标历史柱趋势线预测柱组合图', file: './pivot-chart/combination-forecast.mjs', bundles: ['vchart'] }, + { id: 'pivot-chart-sunburst-hierarchy', purpose: '嵌套层级数据旭日图', file: './pivot-chart/sunburst-hierarchy.mjs', bundles: ['vchart'] }, + { id: 'header-grid-tree-filter-expand', purpose: '筛选插件与三级树形表头点击展开', file: './header/grid-tree-filter-expand.mjs', bundles: ['plugins'] }, + { id: 'promise-custom-merge', purpose: '异步批次数据中的多行多列自定义合并', file: './data/promise-custom-merge.mjs', bundles: ['vtable'] }, + { id: 'tree-checkbox-add-record', purpose: '树形行序号复选状态下插入根记录', file: './tree/checkbox-add-record.mjs', bundles: ['vtable'] }, + { id: 'tree-checkbox-delete-record', purpose: '树形行序号复选状态下删除混合路径', file: './tree/checkbox-delete-record.mjs', bundles: ['vtable'] }, + { id: 'sheet-cross-tab-formula', purpose: '跨 Sheet 求和与中文感叹号归一化', file: './sheet/cross-tab-formula.mjs', bundles: ['sheet'] }, + { id: 'drag-column-header', purpose: '多层表头旁普通列鼠标拖动排序', file: './interaction/drag-column-header.mjs', bundles: ['vtable'] }, + { id: 'tree-lazy-record-children', purpose: '展开树节点后事件注入懒加载子记录', file: './tree/lazy-record-children.mjs', bundles: ['vtable'] }, + { id: 'records-add-pagination', purpose: '分页首屏内批量插入记录', file: './records/add-pagination.mjs', bundles: ['vtable'] }, + { id: 'pivot-update-sort-state-click', purpose: '透视排序点击事件回写专用状态', file: './pivot/update-pivot-sort-state-click.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-histogram-color', purpose: '直方图区间颜色域与零值柱', file: './pivot-chart/histogram-color.mjs', bundles: ['vchart'] }, + { id: 'gantt-locate-offscreen-task', purpose: 'Gantt 左右离屏任务定位图标点击滚动', file: './gantt/locate-offscreen-task.mjs', bundles: ['gantt'] }, + { id: 'tree-pagination-double-click', purpose: '树形列表第二页双击事件定位', file: './tree/pagination-double-click.mjs', bundles: ['vtable'] }, + { id: 'sheet-formula-auto-fill-copy', purpose: 'Sheet 公式填充柄拖动和复制填充菜单', file: './sheet/formula-auto-fill-copy.mjs', bundles: ['sheet'] }, + { id: 'select-disable-callback', purpose: '回调按行列禁选单元格', file: './interaction/disable-select-callback.mjs', bundles: ['vtable'] }, + { id: 'gantt-move-task-bar', purpose: 'Gantt 任务条拖动与日期事件', file: './gantt/move-task-bar.mjs', bundles: ['gantt'] }, + { id: 'pivot-initial-column-sort-state', purpose: '透视列树分支初始排序状态与自动填宽', file: './pivot/initial-column-sort-state.mjs', bundles: ['vtable'] }, + { id: 'blank-area-deselect', purpose: '空白区清除选择的双配置切换', file: './interaction/blank-area-deselect.mjs', bundles: ['vtable'] }, + { id: 'disabled-arrow-navigation', purpose: '禁选列与键盘方向导航', file: './keyboard/disabled-arrow-navigation.mjs', bundles: ['vtable'] }, + { id: 'pivot-custom-total-data-tree', purpose: '显式汇总记录的透视树展开', file: './pivot/custom-total-data-tree.mjs', bundles: ['vtable'] }, + { id: 'promise-keep-data', purpose: '异步数据源配置更新时保留数据', file: './data/promise-keep-data.mjs', bundles: ['vtable'] }, + { id: 'pivot-corner-empty-matrix', purpose: '透视表空行空列空指标角头矩阵', file: './pivot/corner-empty-matrix.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-bar-line-right-axis', purpose: '透视柱线图百分比柱宽与左右双轴', file: './pivot-chart/bar-line-right-axis.mjs', bundles: ['vchart'] }, + { id: 'tree-filter-clear-lazy', purpose: '树形列表过滤、懒加载与清除规则', file: './tree/filter-clear-lazy.mjs', bundles: ['vtable'] }, + { id: 'gantt-tree-move-resize', purpose: '树形子任务条移动与拉伸', file: './gantt/tree-move-resize.mjs', bundles: ['gantt'] }, + { id: 'group-add-delete-records', purpose: '两级分组内按路径增删记录', file: './group/add-delete-records.mjs', bundles: ['vtable'] }, + { id: 'drag-row-series-select', purpose: '行序号列纵向拖选', file: './interaction/drag-row-series-select.mjs', bundles: ['vtable'] }, + { id: 'keyboard-cut-paste-event', purpose: '事件剪贴板剪切两格并粘贴', file: './keyboard/cut-paste-event.mjs', bundles: ['vtable'] }, + { id: 'pivot-empty-string-dimension', purpose: '透视空字符串列维度与普通列并存', file: './pivot/empty-string-dimension.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-pie-multi-select', purpose: '透视饼图连续扇区多选', file: './pivot-chart/pie-multi-select.mjs', bundles: ['vchart'] }, + { id: 'resize-row-height', purpose: '列表选择后拖动行边界调整行高', file: './interaction/resize-row-height.mjs', bundles: ['vtable'] }, + { id: 'pivot-resize-indicator-row', purpose: '指标行上的透视表拖动行高', file: './pivot/resize-indicator-row.mjs', bundles: ['vtable'] }, + { id: 'pivot-corner-sort-one-dimension', purpose: '单级角头维度初始降序状态与排序图标', file: './pivot/corner-sort-one-dimension.mjs', bundles: ['vtable'] }, + { id: 'pivot-corner-sort-two-dimensions', purpose: '两级角头维度初始降序状态与排序图标', file: './pivot/corner-sort-two-dimensions.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-circle-packing-hierarchy', purpose: '透视圆形打包图层级数据', file: './pivot-chart/circle-packing-hierarchy.mjs', bundles: ['vchart'] }, + { id: 'layout-min-max-adaptive-width', purpose: '自适应列宽的最小最大值', file: './layout/min-max-adaptive-width.mjs', bundles: ['vtable'] }, + { id: 'pivot-max-frozen-width', purpose: '透视冻结行头宽度上限逐列裁剪', file: './frozen/pivot-max-frozen-width.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-crosshair-linkage-hover', purpose: '横向图表悬停准线联动', file: './pivot-chart/crosshair-linkage-hover.mjs', bundles: ['vchart'] }, + { id: 'pivot-column-header-title', purpose: '透视列表头独立标题行', file: './pivot/column-header-title.mjs', bundles: ['vtable'] }, + { id: 'sort-initial-multiple-state', purpose: 'setRecords 前设置复合初始排序', file: './sort/initial-multiple-state.mjs', bundles: ['vtable'] }, + { id: 'layout-limit-max-auto-width', purpose: '自动列宽最大值开关与数值限制', file: './layout/limit-max-auto-width.mjs', bundles: ['vtable'] }, + { id: 'layout-custom-compute-row-height', purpose: '按记录回调计算行高', file: './layout/custom-compute-row-height.mjs', bundles: ['vtable'] }, + { id: 'frozen-drag-disabled', purpose: '冻结列表头禁拖但普通列仍可移动', file: './frozen/drag-disabled.mjs', bundles: ['vtable'] }, + { id: 'frozen-drag-adjust-count', purpose: '拖动普通列进入冻结区并调整冻结列数', file: './frozen/drag-adjust-count.mjs', bundles: ['vtable'] }, + { id: 'frozen-scroll-columns', purpose: '左右冻结区独立横向滚动', file: './frozen/scroll-frozen-columns.mjs', bundles: ['vtable'] }, + { id: 'tree-checkbox-record-index-clear', purpose: '隐藏树子节点索引取消勾选后清空整列', file: './tree/checkbox-record-index-clear.mjs', bundles: ['vtable'] }, + { id: 'layout-canvas-size-options', purpose: '固定自动限制及更新后的画布尺寸', file: './layout/canvas-size-options.mjs', bundles: ['vtable'] }, + { id: 'tree-zero-height-toggle', purpose: '零高度树子行折叠展开后视口填充', file: './tree/zero-height-toggle.mjs', bundles: ['vtable'] }, + { id: 'pivot-corner-remaining-variants', purpose: '角头其余三种行列指标排列', file: './pivot/corner-remaining-variants.mjs', bundles: ['vtable'] }, + { id: 'pivot-resize-indicator-group', purpose: '指标组行高按比例一起拖动', file: './pivot/resize-indicator-group.mjs', bundles: ['vtable'] }, + { id: 'transpose-only-body-auto-width', purpose: '转置表仅按表体计算自动列宽', file: './transpose/only-body-auto-width.mjs', bundles: ['vtable'] }, +]; + +/** 从当前清单目录加载用例,冻结副本不会回到工作区取代码。 */ +export async function loadCase(item) { + return (await import(new URL(item.file, import.meta.url))).default; +} diff --git a/packages/vtable/__tests__/visual/cases/interaction/blank-area-deselect.mjs b/packages/vtable/__tests__/visual/cases/interaction/blank-area-deselect.mjs new file mode 100644 index 0000000000..568afeff9d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/blank-area-deselect.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 667012bf71989000cfc6dc4d, 6670130571989000cfc6dc4f + * 验证目的:空白区点击是否清除选择,由 blankAreaClickDeselect 的真假控制。 + * 改写:使用固定匿名记录,分别在配置更新前后验证选择状态。 + */ +export default { + mount(container) { + // 短表在 400px 容器中留下可点击的空白区域。 + container.style.height = '400px'; + const records = [{ id: 1, name: 'Item A' }, { id: 2, name: 'Item B' }]; + const columns = [{ field: 'id', title: 'ID', width: 120 }, + { field: 'name', title: 'Name', width: 180 }]; + window.__blankOptions = { records, columns }; + return new window.VTable.ListTable(container, { + records, columns, select: { blankAreaClickDeselect: true }, widthMode: 'standard' + }); + }, + async exercise(page) { + // 先验证默认清除行为,再将配置改为 false 并重复点击。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { cell: { x: host.x + (b.x1 + b.x2) / 2, + y: host.y + (b.y1 + b.y2) / 2 }, + blank: { x: host.x + 220, y: host.y + 300 } }; + }); + await page.mouse.click(point.cell.x, point.cell.y); + await page.mouse.click(point.blank.x, point.blank.y); + await page.evaluate(() => { + if (window.__visualTable.getSelectedCellRanges().length) + throw new Error('blankAreaClickDeselect=true 未清除选择'); + window.__visualTable.updateOption({ ...window.__blankOptions, + select: { blankAreaClickDeselect: false }, widthMode: 'standard' }); + }); + await page.mouse.click(point.cell.x, point.cell.y); + await page.mouse.click(point.blank.x, point.blank.y); + }, + async verify(page) { + // false 时点击表格空白处仍保留最后选择的单元格。 + await page.evaluate(() => { + const ranges = window.__visualTable.getSelectedCellRanges(); + if (ranges.length !== 1 || ranges[0].start.col !== 1 || ranges[0].start.row !== 1) + throw new Error(`空白区错误清除了选择:${JSON.stringify(ranges)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/disable-select-callback.mjs b/packages/vtable/__tests__/visual/cases/interaction/disable-select-callback.mjs new file mode 100644 index 0000000000..9eb8f2b835 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/disable-select-callback.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 6747e56a71189400b2ec8dc7 + * 验证目的:disableSelect 回调同时禁选指定行和列,其余单元格可选择。 + * 改写:去掉格式化、排序和主题设置,保留源用例的行列禁选规则与点击顺序。 + */ +export default { + mount(container) { + // 第 2 行和第 2 列由同一个回调决定禁选状态。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 130 }, + { field: 'status', title: 'Status', width: 130 }, + { field: 'progress', title: 'Progress', width: 130 }], + records: Array.from({ length: 5 }, (_, index) => ({ id: index + 1, + name: `Item ${index + 1}`, status: 'Ready', progress: (index + 1) * 20 })), + select: { disableSelect(col, row) { return row === 2 || col === 2; } } + }); + }, + async exercise(page) { + // 依次点击禁选行、禁选列和普通单元格,记录每一步的选择范围。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [[0, 2], [2, 3], [0, 3]].map(([col, row]) => { + const bounds = table.getCellRect(col, row).bounds; + return { x: host.x + (bounds.x1 + bounds.x2) / 2, + y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + }); + await page.evaluate(() => { window.__selectSnapshots = []; }); + for (const point of points) { + await page.mouse.click(point.x, point.y); + await page.evaluate(() => window.__selectSnapshots.push(window.__visualTable.getSelectedCellRanges())); + } + }, + async verify(page) { + // 前两个点击不能选择禁选区域,最后一次应选中普通单元格。 + await page.evaluate(() => { + const [row, col, allowed] = window.__selectSnapshots; + if (row.length || col.length || allowed.length !== 1 || + allowed[0].start.col !== 0 || allowed[0].start.row !== 3) + throw new Error(`disableSelect 回调未生效:${JSON.stringify(window.__selectSnapshots)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/disabled-column-range.mjs b/packages/vtable/__tests__/visual/cases/interaction/disabled-column-range.mjs new file mode 100644 index 0000000000..24b072db6a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/disabled-column-range.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 69cf25dde41b43005d89a623 + * 验证目的:拖选跨过禁选列时,选择范围与高亮不会覆盖该列。 + * 改写:保留 inline 表头选择、cross 高亮和禁选列,使用单元格矩形代替录制像素坐标。 + */ +export default { + mount(container) { + // 固定四列及五行数据,最后一列明确禁止选择。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + select: { headerSelectMode: 'inline', highlightMode: 'cross', highlightInRange: true }, + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'note', title: 'Note', width: 150 }, + { field: 'name', title: 'Name', width: 150, disableSelect: true } + ], + records: [ + { progress: 100, id: 1, note: 'A1', name: 'A' }, + { progress: 80, id: 2, note: 'B2', name: 'B' }, + { progress: 1, id: 3, note: 'C3', name: 'C' }, + { progress: 55, id: 4, note: 'D4', name: 'D' }, + { progress: 28, id: 5, note: 'E5', name: 'E' } + ], + showPin: true, widthMode: 'standard', allowFrozenColCount: 2 + }); + }, + async exercise(page) { + // 复现来源中从首列拖至禁选列的动作。 + const points = await page.evaluate(() => { + const host = document.getElementById('table').getBoundingClientRect(); + return [[0, 1], [3, 4]].map(([col, row]) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + }); + await page.mouse.move(points[0].x, points[0].y); + await page.mouse.down(); + await page.mouse.move(points[1].x, points[1].y, { steps: 8 }); + await page.mouse.up(); + }, + async verify(page) { + // 至少选择一个单元格,并检查范围没有进入禁选列。 + await page.evaluate(() => { + const ranges = window.__visualTable.getSelectedCellRanges(); + if (!ranges.length || ranges.some(range => Math.max(range.start.col, range.end.col) >= 3)) + throw new Error(`禁选列进入选择范围:${JSON.stringify(ranges)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/drag-column-header.mjs b/packages/vtable/__tests__/visual/cases/interaction/drag-column-header.mjs new file mode 100644 index 0000000000..e39eab959f --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/drag-column-header.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 646492b0917f340071e15c6e + * 验证目的:分组表头旁的普通列经鼠标拖动后,表头顺序和表体仍一致。 + * 改写:人员与邮箱数据替换为固定通用字段,保留多层表头和 column 拖动模式。 + */ +export default { + mount(container) { + // 来源的 Name 分组位于两个普通列之间,拖动末列可检验整个列结构更新。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 140 }, + { title: 'Name', columns: [ + { field: 'first', title: 'First', width: 130 }, + { field: 'last', title: 'Last', width: 130 } + ] }, + { field: 'contact', title: 'Contact', width: 160 }, + { field: 'date', title: 'Date', width: 120 } + ], + records: Array.from({ length: 8 }, (_, index) => ({ progress: index * 13, + first: `First ${index + 1}`, last: `Last ${index + 1}`, + contact: `contact-${index + 1}`, date: `2024-01-${String(index + 1).padStart(2, '0')}` })), + dragHeaderMode: 'column', widthMode: 'standard' + }); + }, + async exercise(page) { + // 从 Contact 的顶层表头拖到 Progress 左侧,重放来源中的真实列移动。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [[3, 0], [0, 0]].map(([col, row]) => { + const bounds = table.getCellRect(col, row).bounds; + return { x: host.x + (bounds.x1 + bounds.x2) / 2, + y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + }); + // 来源先点击表头建立可拖动的整列选区。 + await page.mouse.click(points[0].x, points[0].y); + await page.mouse.move(points[0].x, points[0].y); + await page.mouse.down(); + await page.mouse.move(points[1].x, points[1].y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // Contact 应移动至 Progress 前面,首行值与字段定义同步。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getHeaderField(0, 0) !== 'contact' || table.getCellValue(0, 2) !== 'contact-1') + throw new Error(`拖动后列顺序错误:${table.columns.map(column => column.field ?? column.title)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-select.mjs b/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-select.mjs new file mode 100644 index 0000000000..ca65d5c884 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-select.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 67174920f4fe9100b2ce7d33 + * 验证目的:在行序号列纵向拖动可选中连续多行。 + * 改写:原人员记录替换为顺序数字,保留行序号 dragOrder 配置和真实拖动。 + */ +export default { + mount(container) { + // 充足行数使拖动选择能够覆盖多个完整表体行。 + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'label', title: 'Label', width: 180 }, + { field: 'value', title: 'Value', width: 140 }], + records: Array.from({ length: 8 }, (_, index) => ({ + label: `Item ${index + 1}`, value: index + 1 + })), + rowSeriesNumber: { title: 'No.', dragOrder: true, width: 60 }, + select: { highlightMode: 'row' } + }); + }, + async exercise(page) { + // 从首个行序号拖到第四个行序号,保持鼠标按下跨过两条以上记录。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [1, 4].map(row => { + const b = table.getCellRect(0, row).bounds; + return { x: host.x + (b.x1 + b.x2) / 2, + y: host.y + (b.y1 + b.y2) / 2 }; + }); + }); + await page.mouse.move(points[0].x, points[0].y); + await page.mouse.down(); + await page.mouse.move(points[1].x, points[1].y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // 拖动后的选择至少跨越两行;像素比较检查序号列高亮。 + await page.evaluate(() => { + const ranges = window.__visualTable.getSelectedCellRanges(); + if (!ranges.some(range => range.end.row - range.start.row >= 2)) + throw new Error(`行序号拖选未覆盖连续行:${JSON.stringify(ranges)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/resize-row-height.mjs b/packages/vtable/__tests__/visual/cases/interaction/resize-row-height.mjs new file mode 100644 index 0000000000..8f7e1c1f0c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/resize-row-height.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 662e1f56d4511700f6885622 + * 验证目的:鼠标拖动列表行边界后行高实际增加,选择状态不阻碍调整。 + * 改写:来源的多列表数据缩为匿名短记录,保留两次动作中的选中后拖动。 + */ +export default { + mount(container) { + // 固定初始行高使拉伸后的变化可以数值断言。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 150 }, + { field: 'value', title: 'Value', width: 150 }], + records: Array.from({ length: 5 }, (_, index) => ({ + name: `Item ${index + 1}`, value: index + 1 + })), defaultRowHeight: 32, resize: { rowResizeMode: 'all' } + }); + }, + async exercise(page) { + // 先选中第一数据行,再在行边界向下拖动 32px。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const b = table.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__rowHeightBefore = b.y2 - b.y1; + return { cell: { x: host.x + (b.x1 + b.x2) / 2, + y: host.y + (b.y1 + b.y2) / 2 }, + edge: { x: host.x + (b.x1 + b.x2) / 2, y: host.y + b.y2 + 1 } }; + }); + await page.mouse.click(point.cell.x, point.cell.y); + await page.mouse.move(point.edge.x, point.edge.y); + await page.mouse.down(); + await page.mouse.move(point.edge.x, point.edge.y + 32, { steps: 10 }); + await page.mouse.up(); + }, + async verify(page) { + // 源行的画布矩形必须增高,后续行随之下移。 + await page.evaluate(() => { + const table = window.__visualTable; + const first = table.getCellRect(1, 1).bounds; + const second = table.getCellRect(1, 2).bounds; + if (first.y2 - first.y1 < window.__rowHeightBefore + 15 || second.y1 < first.y2 - 1) + throw new Error(`列表行高未调整:${JSON.stringify({ before: window.__rowHeightBefore, first, second })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-cross.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-cross.mjs new file mode 100644 index 0000000000..8ba660a364 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-cross.mjs @@ -0,0 +1,34 @@ +/** + * BugServer case IDs: 665eb79dfaec2700ad749550 + * 验证目的:cross 选择模式下先点表体、再点表头,各自生成有效选择范围。 + * 改写:将录制坐标替换为单元格矩形定位,并逐步断言两个录制动作。 + */ +export default { + mount(container) { + // 固定表格数据和 cross 模式,供两个顺序点击使用。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, { field: 'name', title: 'Name', width: 150 }], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }], + select: { highlightMode: 'cross' }, hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 两次操作分别对应 BugServer 录制的表体和表头点击。 + const clickCell = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const bounds = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await clickCell(1, 1); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 1); + await clickCell(1, 0); + }, + async verify(page) { + // 最终选择必须落在表头;表体动作已在 exercise 中单独验证。 + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 0); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/keyboard/copy-paste-event.mjs b/packages/vtable/__tests__/visual/cases/keyboard/copy-paste-event.mjs new file mode 100644 index 0000000000..9c255d5e78 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/keyboard/copy-paste-event.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6a8c0450aa6e45005ce41013 + * 验证目的:列表复制一格后,粘贴事件把文本写入另一行的空单元格。 + * 改写:使用本地事件剪贴板代替宿主 clipboard 权限;保留实际 copy/paste 事件路径。 + */ +export default { + mount(container) { + // 目标格初始为空,不能由现有记录误判为粘贴成功。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 120, editor: 'input' }, + { field: 'age', title: 'Age', width: 100, editor: 'input' }, + { field: 'city', title: 'City', width: 140, editor: 'input' }], + records: [{ name: 'Source', age: 'A1', city: 'Source' }, + { name: '', age: '', city: 'Target row' }], + keyboardOptions: { copySelected: true, pasteValueToCell: true }, + editCellTrigger: ['keydown', 'dblclick'] + }); + }, + async exercise(page) { + // 和来源一样先选中源格复制,再选中目标格派发 paste。 + await page.evaluate(() => { + const table = window.__visualTable; + const element = table.getElement(); + const store = {}; + const clipboardData = { setData(type, value) { store[type] = String(value); }, + getData(type) { return store[type] || ''; }, clearData(type) { delete store[type]; } }; + const event = type => { + const value = new Event(type, { bubbles: true, cancelable: true }); + Object.defineProperty(value, 'clipboardData', { value: clipboardData }); + return value; + }; + table.selectCell(0, 1); + element.focus(); + element.dispatchEvent(event('copy')); + window.__listCopiedText = store['text/plain'] || store.text || ''; + table.selectCell(0, 2); + element.dispatchEvent(event('paste')); + }); + }, + async verify(page) { + // 复制文本与目标格都须等于源格,缺动作时断言失败。 + await page.waitForFunction(() => { + const table = window.__visualTable; + return window.__listCopiedText?.trim() === 'Source' && table.getCellValue(0, 2) === 'Source'; + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/keyboard/cut-paste-event.mjs b/packages/vtable/__tests__/visual/cases/keyboard/cut-paste-event.mjs new file mode 100644 index 0000000000..e66e8a71ae --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/keyboard/cut-paste-event.mjs @@ -0,0 +1,59 @@ +/** + * BugServer case IDs: 6a8c0450eb8e12005e80be38 + * 验证目的:剪切两格时事件剪贴板写入原值、清空源格,再粘贴到目标行。 + * 改写:用浏览器内存事件剪贴板代替系统权限,记录只含固定短文本。 + */ +export default { + mount(container) { + // 两列连续源格和同列空目标格构成最小剪切粘贴场景。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 140, editor: 'input' }, + { field: 'city', title: 'City', width: 140, editor: 'input' }], + records: [{ name: 'Alpha', city: 'North' }, + { name: 'Beta', city: 'South' }, + { name: '', city: '' }], + keyboardOptions: { copySelected: true, cutSelected: true, pasteValueToCell: true }, + editCellTrigger: ['keydown', 'dblclick'] + }); + }, + async exercise(page) { + // 明确走 ClipboardEvent 回退路径,保留 cut 和 paste 的实际事件处理。 + await page.evaluate(async () => { + const table = window.__visualTable; + Object.defineProperty(navigator, 'clipboard', { configurable: true, value: undefined }); + const store = {}; + const clipboardData = { setData(type, value) { store[type] = String(value); return true; }, + getData(type) { return store[type] || ''; }, + clearData(type) { if (type) delete store[type]; else Object.keys(store).forEach(key => delete store[key]); } }; + const event = type => { + const value = new Event(type, { bubbles: true, cancelable: true }); + Object.defineProperty(value, 'clipboardData', { value: clipboardData }); + return value; + }; + table.selectCells([{ start: { col: 0, row: 1 }, end: { col: 1, row: 1 } }]); + window.__cutExpected = table.getCopyValue(); + const input = document.querySelector('#table input.table-focus-control'); + if (input) { input.removeAttribute('readonly'); input.value = 'placeholder'; input.focus(); input.select(); } + table.getElement().focus(); + table.getElement().dispatchEvent(event('cut')); + await new Promise(resolve => setTimeout(resolve, 150)); + window.__cutText = store['text/plain'] || store.text || ''; + table.selectCell(0, 3); + table.getElement().focus(); + table.getElement().dispatchEvent(event('paste')); + await new Promise(resolve => setTimeout(resolve, 150)); + }); + }, + async verify(page) { + // 数据源、复制文本和目标两格都必须反映真实的剪切结果。 + await page.evaluate(() => { + const table = window.__visualTable; + const state = { expected: window.__cutExpected, copied: window.__cutText, + source: [table.getCellValue(0, 1), table.getCellValue(1, 1)], + target: [table.getCellValue(0, 3), table.getCellValue(1, 3)] }; + if (state.copied !== state.expected || state.source.join('|') !== '|' || + state.target.join('|') !== 'Alpha|North') + throw new Error(`剪切粘贴状态异常:${JSON.stringify(state)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/keyboard/disabled-arrow-navigation.mjs b/packages/vtable/__tests__/visual/cases/keyboard/disabled-arrow-navigation.mjs new file mode 100644 index 0000000000..6bad7e5c19 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/keyboard/disabled-arrow-navigation.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 6697b10caeb8a00109f2ddb3, 6697b191aeb8a00109f2ddb4 + * 验证目的:键盘向左跳过禁选列,向上到表头时选中可用的整列。 + * 改写:保留禁选首列与键盘操作,记录改为连续匿名编号。 + */ +export default { + mount(container) { + // 首列禁止选择,其余两列允许键盘导航。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 120, disableSelect: true }, + { field: 'name', title: 'Name', width: 160 }, + { field: 'score', title: 'Score', width: 120 }], + records: Array.from({ length: 4 }, (_, i) => ({ id: i + 1, + name: `Item ${i + 1}`, score: (i + 1) * 10 })) + }); + table.getElement().tabIndex = 0; + return table; + }, + async exercise(page) { + // 两个方向分别从源用例相同的单元格起点发出原生键盘事件。 + await page.evaluate(() => { + const table = window.__visualTable; + table.selectCell(1, 2); + table.getElement().focus(); + }); + await page.keyboard.press('Control+ArrowLeft'); + await page.evaluate(() => { + window.__leftRanges = window.__visualTable.getSelectedCellRanges(); + window.__visualTable.selectCell(1, 1); + window.__visualTable.getElement().focus(); + }); + await page.keyboard.press('ArrowUp'); + }, + async verify(page) { + // 向左保持在可选列,向上进入表头后只能选择当前整列。 + await page.evaluate(() => { + const left = window.__leftRanges; + const up = window.__visualTable.getSelectedCellRanges(); + if (!left.length || left.some(range => range.start.col === 0 || range.end.col === 0) || + up.length !== 1 || up[0].start.col !== 1 || up[0].end.col !== 1 || + up[0].start.row !== 0 || up[0].end.row !== 4) + throw new Error(`禁选导航结果异常:${JSON.stringify({ left, up })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/keyboard/select-all-body.mjs b/packages/vtable/__tests__/visual/cases/keyboard/select-all-body.mjs new file mode 100644 index 0000000000..06cbdb1cdc --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/keyboard/select-all-body.mjs @@ -0,0 +1,49 @@ +/** + * BugServer case IDs: 665ed085faec2700ad74955b + * 验证目的:Ctrl/Command+A 选中表体时,disableHeaderSelect 排除表头。 + * 改写:来源虽无 interactions 字段,但源码会自行派发 keydown;保留该事件路径并移除远程编辑器加载。 + */ +export default { + mount(container) { + // 固定三列与三行,便于检查全选范围的上下边界。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + columns: [ + { field: 'name', title: 'Name', width: 150 }, + { field: 'date', title: 'Date', width: 150 }, + { field: 'id', title: 'ID', width: 100 } + ], + records: [ + { name: 'A', date: '2019-01-01', id: 1 }, + { name: 'B', date: '2020-02-02', id: 2 }, + { name: 'C', date: '2021-03-03', id: 3 } + ], + keyboardOptions: { copySelected: true, pasteValueToCell: true, + selectAllOnCtrlA: { disableHeaderSelect: true } } + }); + }, + async exercise(page) { + // 来源先选局部区域,再向表格根元素派发组合键事件。 + await page.evaluate(() => { + const table = window.__visualTable; + table.selectCells([{ start: { col: 0, row: 2 }, end: { col: 2, row: 3 } }]); + table.getElement().tabIndex = 0; + table.getElement().focus(); + const event = document.createEvent('Event'); + event.initEvent('keydown', true, false); + Object.assign(event, { ctrlKey: true, metaKey: true, altKey: true, + which: 67, keyCode: 67, key: 'a', code: 'KeyA' }); + table.getElement().dispatchEvent(event); + }); + }, + async verify(page) { + // 全选覆盖表体首末行,且任一范围都不含第零行表头。 + await page.evaluate(() => { + const table = window.__visualTable; + const ranges = table.getSelectedCellRanges(); + if (ranges.length !== 1 || ranges[0].start.row !== 1 || ranges[0].end.row !== table.rowCount - 1) + throw new Error(`Ctrl/Command+A 未选中完整表体:${JSON.stringify(ranges)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/language/cyrillic-wrap.mjs b/packages/vtable/__tests__/visual/cases/language/cyrillic-wrap.mjs new file mode 100644 index 0000000000..c91db0fa05 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/language/cyrillic-wrap.mjs @@ -0,0 +1,25 @@ +/** + * BugServer case IDs: 65e69276603de700d1d8b9e5 + * 验证目的:自定义西里尔字母集后多语言文本仍正常换行。 + * 改写:保留西里尔混排结构,文本换成通用示例。 + */ +export default { + mount(container) { + // 测试页逐例隔离,修改全局字母集不会影响其他用例。 + window.VTable.setCustomAlphabetCharSet('БВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯбвгдежзийклмнопрстуфхцчшщъыьэюя'); + return new window.VTable.ListTable(container, { + columns: [{ field: 'latin', title: 'Column 1', width: 'auto' }, + { field: 'cyrillic', title: 'Колонка 2', width: 'auto' }, + { field: 'mixed', title: 'Mixed колонка', width: 100 }], + records: [{ latin: 'Example text with correct wrapping', cyrillic: 'Пример текста на кириллице', + mixed: 'GGGGGGGGGGGGGGGG ЮЮЮЮЮЮЮЮЮЮЮЮЮЮЮЮ' }], + widthMode: 'standard', heightMode: 'autoHeight', autoWrapText: true + }); + }, + async verify(page) { + // 混合字符内容必须进入表格。 + await page.evaluate(() => { + if (!window.__visualTable.getCellValue(2, 1).includes('Ю')) throw new Error('西里尔文本缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/adaptive-width.mjs b/packages/vtable/__tests__/visual/cases/layout/adaptive-width.mjs new file mode 100644 index 0000000000..161fa897bd --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/adaptive-width.mjs @@ -0,0 +1,24 @@ +/** + * BugServer case IDs: 64bdffe85134109a76ccddd9 + * 验证目的:adaptive 模式将多列分配到容器宽度。 + * 改写:使用通用字段,保留定宽列与 adaptive 模式。 + */ +export default { + mount(container) { + // 设定小于容器宽度的列宽,让 adaptive 分配剩余空间。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, fieldFormat: r => `${r.progress}%` }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150 }], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }], + widthMode: 'adaptive', allowFrozenColCount: 2 + }); + }, + async verify(page) { + // 最后一列表头应扩展到接近容器右边界。 + await page.evaluate(() => { + const b = window.__visualTable.getCellRect(2, 0).bounds; + if (b.x2 < 700) throw new Error(`adaptive 宽度不足:${b.x2}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/auto-width-height.mjs b/packages/vtable/__tests__/visual/cases/layout/auto-width-height.mjs new file mode 100644 index 0000000000..37d0ad20a0 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/auto-width-height.mjs @@ -0,0 +1,32 @@ +/** + * BugServer case IDs: 64bdfed95134109a76ccddd6, 64be004b5134109a76ccddda + * 验证目的:autoWidth 列宽与 autoHeight 行高在同一列表上生效。 + * 改写:合并共享记录与列结构的两个来源,保留两种自适应模式。 + */ +export default { + mount(container) { + // 长字段可触发自动测量,固定输入保证双侧结果可比较。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'name', title: 'Name', width: 'auto' }, + { field: 'description', title: 'Description', width: 'auto', style: { autoWrapText: true } }, + { field: 'value', title: 'Value', width: 'auto' } + ], + records: [ + { name: 'A', description: 'A long description that wraps inside a measured column.', value: 10 }, + { name: 'B', description: 'Another fixed description.', value: 20 } + ], + widthMode: 'autoWidth', heightMode: 'autoHeight', autoWrapText: true, + allowFrozenColCount: 2 + }); + }, + async verify(page) { + // 检查测量后的尺寸是有限的正值,而非仅检查配置。 + await page.evaluate(() => { + const table = window.__visualTable; + if (!(table.getColWidth(1) > 0) || !(table.getRowHeight(1) > 0)) + throw new Error('自适应尺寸无效'); + if (table.getCellValue(0, 2) !== 'B') throw new Error('自适应表格数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/canvas-size-options.mjs b/packages/vtable/__tests__/visual/cases/layout/canvas-size-options.mjs new file mode 100644 index 0000000000..4084311f1c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/canvas-size-options.mjs @@ -0,0 +1,63 @@ +/** + * BugServer case IDs: 678620838e768100b114c398, 6786222198804d00b1d62177, 67862349af3eab00b234917d, 678624597020de00b01c0b49 + * 验证目的:固定、自动、最大限制及 updateOption 后的 canvas 尺寸分别生效。 + * 改写:来源的多组重复人员列缩为三列八行匿名数值。 + */ +export default { + mount(container) { + // 四张列表共用输入,分别展示固定尺寸、内容自动撑开、上限和配置更新。 + container.style.width = '800px'; + container.style.height = '900px'; + container.style.display = 'grid'; + container.style.gridTemplateColumns = '1fr 1fr'; + const options = { + columns: [0, 1, 2].map(index => ({ field: `c${index}`, title: `Column ${index}`, width: 180 })), + records: Array.from({ length: 8 }, (_, row) => ({ c0: row, c1: row + 10, c2: row + 20 })), + defaultRowHeight: 42, widthMode: 'standard' + }; + const variants = [ + { canvasWidth: 300, canvasHeight: 200 }, + { canvasWidth: 'auto', canvasHeight: 'auto' }, + { canvasWidth: 'auto', canvasHeight: 'auto', maxCanvasWidth: 500, maxCanvasHeight: 300 }, + { canvasWidth: 200, canvasHeight: 160 } + ]; + const tables = variants.map(variant => { + const host = document.createElement('div'); + host.style.cssText = 'width:390px;height:440px;overflow:hidden'; + container.append(host); + return new window.VTable.ListTable(host, { ...options, ...variant }); + }); + return { + tables, + updateTarget() { + // 模拟来源中先用固定尺寸构造,再切到内容自适应的配置更新。 + return tables[3].updateOption({ ...options, canvasWidth: 'auto', canvasHeight: 'auto' }); + }, + async renderAsync() { + // 等待所有画布的首次绘制。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 每张表在快照结束后独立释放。 + tables.forEach(table => table.release()); + } + }; + }, + async exercise(page) { + // 自动尺寸在内部异步计算,待其完成后切换第四张表。 + await page.waitForFunction(() => window.__visualTable.tables[1].canvasWidth > 500); + await page.evaluate(() => window.__visualTable.updateTarget()); + await page.waitForFunction(() => window.__visualTable.tables[3].canvasWidth > 500); + }, + async verify(page) { + // 四种配置的实际宽高须符合固定值、自动增长及最大值边界。 + await page.evaluate(() => { + const sizes = window.__visualTable.tables.map(table => [table.canvasWidth, table.canvasHeight]); + if (Math.abs(sizes[0][0] - 300) > 2 || Math.abs(sizes[0][1] - 200) > 2 || + sizes[1][0] <= 500 || sizes[1][1] <= 300 || + sizes[2][0] > 501 || sizes[2][1] > 301 || + sizes[3][0] <= 500 || sizes[3][1] <= 300) + throw new Error(`画布尺寸选项未生效:${JSON.stringify(sizes)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/container-fit-both.mjs b/packages/vtable/__tests__/visual/cases/layout/container-fit-both.mjs new file mode 100644 index 0000000000..d78879ae2a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/container-fit-both.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 684bf27f12d99200a8e2dd42 + * 验证目的:autoWidth 与 containerFit=true 同时启用时宽高都适配固定容器。 + * 改写:保留布尔配置和固定宿主尺寸,缩减重复展示字段。 + */ +export default { + mount(container) { + // 固定容器后使用布尔适配,区分已有的仅适配高度场景。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150 }], + records: [100, 80, 1, 55, 28].map((progress, i) => ({ progress, id: i + 1, name: `Name ${i + 1}` })), + widthMode: 'autoWidth', containerFit: true, showPin: true, allowFrozenColCount: 2 + }); + }, + async verify(page) { + // 适配后末条记录和表格宽高都必须有效;具体布局交给截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 5) !== 28 || table.tableNoFrameWidth <= 0 || table.tableNoFrameHeight <= 0) + throw new Error('布尔 containerFit 适配失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/container-fit-height.mjs b/packages/vtable/__tests__/visual/cases/layout/container-fit-height.mjs new file mode 100644 index 0000000000..37d64e2f9b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/container-fit-height.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 684bf2cd228c0a00a7015501 + * 验证目的:autoWidth 与 containerFit.height 同时启用时,列表适配容器。 + * 改写:缩减展示字段,保留高度单独适配的对象形式。 + */ +export default { + mount(container) { + // 明确固定宿主尺寸,触发与普通 autoWidth 不同的高度适配。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100, sort: true }, { field: 'name', title: 'Name', width: 150 }], + records: [100, 80, 1, 55, 28].map((progress, i) => ({ progress, id: i + 1, name: `Name ${i + 1}` })), + widthMode: 'autoWidth', containerFit: { height: true }, allowFrozenColCount: 2 + }); + }, + async verify(page) { + // 记录和配置必须有效,容器适配外观由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 5) !== 28 || table.rowCount !== 6) + throw new Error('高度适配场景未完成绘制'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/custom-compute-row-height.mjs b/packages/vtable/__tests__/visual/cases/layout/custom-compute-row-height.mjs new file mode 100644 index 0000000000..baae1f6a4a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/custom-compute-row-height.mjs @@ -0,0 +1,28 @@ +/** + * BugServer case IDs: 673c5cad013a5500b2fe99e1 + * 验证目的:customComputeRowHeight 能按记录将指定数据行设为独立高度。 + * 改写:去除来源的邮箱和 SVG,仅保留一列匿名记录及高度回调。 + */ +export default { + mount(container) { + // 第二条记录使用 160px,其他数据行使用 40px。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'item', title: 'Item', width: 220 }], + records: [{ item: 'First' }, { item: 'Tall' }, { item: 'Third' }], + defaultRowHeight: 'auto', + customComputeRowHeight({ row, table }) { + // 回调按当前可见行对应的记录返回固定高度。 + return table.getRecordByCell(0, row)?.item === 'Tall' ? 160 : 40; + } + }); + }, + async verify(page) { + // 第二条记录高于前后记录,且场景图矩形反映相同高度。 + await page.evaluate(() => { + const table = window.__visualTable; + const heights = [1, 2, 3].map(row => table.getRowHeight(row)); + if (heights[1] < 150 || heights[0] > 50 || heights[2] > 50) + throw new Error(`自定义行高错误:${JSON.stringify(heights)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/key-size-config.mjs b/packages/vtable/__tests__/visual/cases/layout/key-size-config.mjs new file mode 100644 index 0000000000..62311f51e5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/key-size-config.mjs @@ -0,0 +1,28 @@ +/** + * BugServer case IDs: 6909e268711d9200a827cd92, 6909e3c4711d9200a827cd93 + * 验证目的:稳定 key 的列宽、行高配置同时覆盖百分比宽度和自动填高。 + * 改写:两条来源共用后者的配置超集,个人字段换成通用名称。 + */ +export default { + mount(container) { + // key 0/1/2 与列宽、行高配置逐一对应。 + return new window.VTable.ListTable(container, { + columns: [{ key: 0, field: 'progress', title: 'Progress', width: 'calc(20% - 20px)' }, + { title: 'Name', columns: [{ key: 1, field: 'first', title: 'First', width: '20%' }, + { key: 2, field: 'last', title: 'Last', width: '20%' }] }], + records: [{ progress: 20, first: 'A', last: 'One' }, { progress: 80, first: 'B', last: 'Two' }], + dragHeaderMode: 'column', autoFillHeight: true, + columnWidthConfig: [{ key: 0, width: 150 }, { key: 1, width: 150 }, { key: 2, width: 150 }], + rowHeightConfig: [{ key: 0, height: 150 }, { key: 1, height: 150 }, { key: 2, height: 150 }] + }); + }, + async verify(page) { + // 第一列宽度和首条记录高度应使用 key 配置。 + await page.evaluate(() => { + const table = window.__visualTable; + const b = table.getCellRect(0, 1).bounds; + if (Math.abs((b.x2 - b.x1) - 150) > 2 || b.y2 - b.y1 < 100) + throw new Error(`key 尺寸配置未生效:${b.x2 - b.x1} × ${b.y2 - b.y1}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/limit-max-auto-width.mjs b/packages/vtable/__tests__/visual/cases/layout/limit-max-auto-width.mjs new file mode 100644 index 0000000000..46bf1e3738 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/limit-max-auto-width.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 64b9f06824402a7e07da8e3c, 6559c7c838a83fc5d23015a4 + * 验证目的:autoWidth 的最大宽度限制在 false 与 100 配置下确实不同。 + * 改写:来源的格式化个人记录改为单个固定长文本单元格。 + */ +export default { + mount(container) { + // 两张列表只有最大自动列宽限制不同,便于直接比较实测列宽。 + container.style.width = '800px'; + container.style.height = '310px'; + container.style.display = 'grid'; + container.style.gridTemplateColumns = '1fr 1fr'; + const tables = [false, 100].map(limitMaxAutoWidth => { + const host = document.createElement('div'); + host.style.cssText = 'width:390px;height:300px'; + container.append(host); + return new window.VTable.ListTable(host, { + columns: [{ field: 'text', title: 'Description', width: 'auto' }], + records: [{ text: 'A long anonymous description that requires a much wider automatically sized column' }], + widthMode: 'autoWidth', limitMaxAutoWidth + }); + }); + return { + tables, + async renderAsync() { + // 等待自动列宽计算和绘制完成。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 比较完成后释放两张列表。 + tables.forEach(table => table.release()); + } + }; + }, + async verify(page) { + // 关闭限制时的实测宽度应明显超过 100,另一张应被限制。 + await page.evaluate(() => { + const [unlimited, capped] = window.__visualTable.tables; + const widths = [unlimited.getColWidth(0), capped.getColWidth(0)]; + if (widths[0] <= widths[1] + 80 || widths[1] > 101) + throw new Error(`自动列宽上限未区分:${JSON.stringify(widths)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/min-max-adaptive-width.mjs b/packages/vtable/__tests__/visual/cases/layout/min-max-adaptive-width.mjs new file mode 100644 index 0000000000..581842ac51 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/min-max-adaptive-width.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 66f28be2885776011c598a30 + * 验证目的:自适应列宽同时遵守各列的 minWidth 和 maxWidth。 + * 改写:使用短文本和长文本的固定记录,去除来源的大型样式及数据。 + */ +export default { + mount(container) { + // 三列均允许自动测量,但宽度应在 100px 至 150px 之间。 + container.style.width = '430px'; + container.style.height = '300px'; + return new window.VTable.ListTable(container, { + columns: [ + { field: 'short', title: 'Short', width: 'auto', minWidth: 100, maxWidth: 150 }, + { field: 'long', title: 'Long label', width: 'auto', minWidth: 100, maxWidth: 150 }, + { field: 'mixed', title: 'Mixed', width: 'auto', minWidth: 100, maxWidth: 150 } + ], + records: [ + { short: 'A', long: 'A deliberately long text value for auto width', mixed: 'B' }, + { short: 'C', long: 'Another long text value', mixed: 'D' } + ], + widthMode: 'adaptive', heightMode: 'autoHeight', autoWrapText: true + }); + }, + async verify(page) { + // 实际计算后的三列宽度必须同时满足上下限。 + await page.evaluate(() => { + const table = window.__visualTable; + const widths = [0, 1, 2].map(col => table.getColWidth(col)); + if (widths.some(width => width < 100 || width > 150)) + throw new Error(`自适应列宽越界:${JSON.stringify(widths)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/menu/disabled-item.mjs b/packages/vtable/__tests__/visual/cases/menu/disabled-item.mjs new file mode 100644 index 0000000000..bdac43c51f --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/menu/disabled-item.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 67fcb22b3376ca00a6024ff8 + * 验证目的:表头下拉菜单的子项可显示禁用状态。 + * 改写:缩短无关 SVG 和展示字段,保留 HTML 菜单、嵌套项及悬停点击顺序。 + */ +export default { + mount(container) { + // 长标题用于覆盖菜单避让,子菜单第二项禁用。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'value', title: 'Value', width: 150 }, { field: 'name', title: 'Name', width: 150 }], + records: [{ value: 10, name: 'A' }], + menu: { renderMode: 'html', defaultHeaderMenuItems: [{ text: 'Sort options with long title', children: [ + { text: 'Ascending', menuKey: 'asc' }, { text: 'Descending', menuKey: 'desc', disabled: true } + ] }] } + }); + }, + async exercise(page) { + // 鼠标到首列表头右边缘,点击菜单图标,再悬停父菜单项。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(0, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x2 - 12, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.click(point.x, point.y); + await page.locator('.vtable__menu-element__item').filter({ hasText: 'Sort options with long title' }).first().hover(); + }, + async verify(page) { + // 子菜单必须出现,Descending 带禁用样式。 + await page.waitForFunction(() => [...document.querySelectorAll('.vtable__menu-element__item-disabled')] + .some(item => item.textContent?.includes('Descending'))); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/menu/dropdown-highlight.mjs b/packages/vtable/__tests__/visual/cases/menu/dropdown-highlight.mjs new file mode 100644 index 0000000000..718847a559 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/menu/dropdown-highlight.mjs @@ -0,0 +1,32 @@ +/** + * BugServer case IDs: 65d4959b97cc3d008de5b594 + * 验证目的:列下拉菜单设置高亮项后,同时绘制菜单状态图标。 + * 改写:个人信息和长 SVG 改为通用数据与本地小图标,保留三个图标属性及 ROW_DESC 菜单键。 + */ +export default { + mount(container) { + // 菜单项的普通、选中、状态图标分别配置,再标记降序项高亮。 + const triangle = ''; + const selected = ''; + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 80 }, + { field: 'code', title: 'Code', width: 180, dropDownMenu: [ + { text: 'Descending', menuKey: 'ROW_DESC', icon: { svg: triangle }, + selectedIcon: { svg: selected }, stateIcon: { svg: selected } }, + { text: 'Ascending', menuKey: 'ROW_ASC', icon: { svg: triangle } } + ] }], + records: [{ id: 1, code: 'A' }, { id: 2, code: 'B' }, { id: 3, code: 'C' }] + }); + table.setDropDownMenuHighlight([{ row: 0, col: 1, menuKey: 'ROW_DESC' }]); + return table; + }, + async verify(page) { + // 菜单高亮状态和表体记录必须同时保留,状态图标交由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + const state = table.stateManager.menu.dropDownMenuHighlight; + if (state?.[0]?.menuKey !== 'ROW_DESC' || state[0].col !== 1 || table.getCellValue(1, 1) !== 'A') + throw new Error('下拉菜单高亮状态未建立'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/bar-line-right-axis.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/bar-line-right-axis.mjs new file mode 100644 index 0000000000..1b56eaa280 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/bar-line-right-axis.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 65a8a7d436599cd39121a863, 67287bffe4bb4400b299cba7, 692904557eb69c005d1e0a18 + * 验证目的:百分比柱宽与按 seriesId 分配的左右轴可在柱线透视图中绘制。 + * 改写:两个指标分成固定数据流,保留柱宽字符串、seriesId 数组和右轴。 + */ +export default { + mount(container) { + // 每个指标拥有独立数据流,避免一侧轴吞掉另一侧的图元。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + rows: [], columns: [], indicatorsAsCol: false, + records: [ + { period: 'A', amount: 10 }, { period: 'B', amount: 18 }, + { period: 'C', amount: 13 }, { period: 'A', rate: 0.2 }, + { period: 'B', rate: 0.6 }, { period: 'C', rate: 0.4 } + ], + indicators: [ + { indicatorKey: 'amount', title: 'Amount', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'common', + series: [{ id: 'amount', type: 'bar', data: { id: 'amount' }, + xField: 'period', yField: 'amount', barWidth: '100%' }], + axes: [{ orient: 'left', seriesId: ['amount'], min: 0 }] } }, + { indicatorKey: 'rate', title: 'Rate', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'common', + series: [{ id: 'rate', type: 'line', data: { id: 'rate' }, + xField: 'period', yField: 'rate', point: { visible: true } }], + axes: [{ orient: 'right', seriesId: ['rate'], min: 0, max: 1 }] } } + ], + defaultRowHeight: 180, defaultColWidth: 560, + widthMode: 'autoWidth', heightMode: 'autoHeight' + }); + }, + async verify(page) { + // 两种图元都要占据可见图表单元格,避免只比较空轴。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts !== 2) throw new Error(`双轴图表单元格数量错误:${charts}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot-horizontal.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot-horizontal.mjs new file mode 100644 index 0000000000..13580d8e91 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot-horizontal.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 690325fb1ef44500a8bec374 + * 验证目的:箱线图水平布局在两级列维度中绘制有无离群点的数据。 + * 改写:缩减重复分组记录,保留六个分位数字段、水平轴和两级列维度。 + */ +export default { + mount(container) { + // 图表模块从本地 bundle 注册,箱线图方向为 horizontal。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + columns: [{ dimensionKey: 'country', title: 'Country' }, { dimensionKey: 'region', title: 'Region' }], + rows: [{ dimensionKey: 'category', title: 'Category' }], + indicators: [{ indicatorKey: 'max', title: 'Distribution', cellType: 'chart', chartModule: 'vchart', + style: { padding: 1 }, chartSpec: { type: 'boxPlot', data: { id: 'dataId' }, + yField: 'item', minField: 'min', q1Field: 'q1', medianField: 'median', + q3Field: 'q3', maxField: 'max', outliersField: 'outliers', direction: 'horizontal', + boxPlot: { style: { shaftShape: 'line', lineWidth: 2 } } } }], + records: [{ country: 'A', region: 'South', category: 'Device', item: 'Type 1', + min: 4.72, q1: 9.73, median: 10.17, q3: 10.51, max: 11.64, outliers: [12.01, 12.02, 14.03] }, + { country: 'A', region: 'North', category: 'Device', item: 'Type 1', + min: 9.4, q1: 10.06, median: 10.75, q3: 11.56, max: 12.5 }, + { country: 'B', region: 'East', category: 'Device', item: 'Type 2', + min: 8.74, q1: 9.46, median: 10.35, q3: 10.94, max: 12.21 }], + indicatorsAsCol: true, defaultRowHeight: 200, defaultHeaderRowHeight: 30, + defaultColWidth: 280, defaultHeaderColWidth: [80, 'auto', 'auto'], + corner: { titleOnDimension: 'row', headerStyle: { autoWrapText: true, padding: 0 } } + }); + }, + async verify(page) { + // 水平箱线图至少占据两个分组单元格。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('水平箱线图单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot.mjs new file mode 100644 index 0000000000..40b5bbeda8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/box-plot.mjs @@ -0,0 +1,48 @@ +/** + * BugServer case IDs: 690325586319a600a9810142 + * 验证目的:PivotChart 的 boxPlot 指标在两级行维度中渲染有离群点和无离群点的数据。 + * 改写:用固定通用类别代替产品文字,保留六个分位数字段的顺序与离群点条件。 + */ +export default { + mount(container) { + // VChart 使用本地 bundle 注册,浏览器不会访问 BugServer 的 CDN。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + rows: [{ dimensionKey: 'group', title: 'Group' }, { dimensionKey: 'region', title: 'Region' }], + columns: [{ dimensionKey: 'category', title: 'Category' }], + indicators: [{ + indicatorKey: 'max', title: 'Distribution', cellType: 'chart', chartModule: 'vchart', + style: { padding: 1 }, + chartSpec: { + type: 'boxPlot', data: { id: 'dataId' }, xField: 'item', + minField: 'min', q1Field: 'q1', medianField: 'median', q3Field: 'q3', + maxField: 'max', outliersField: 'outliers', direction: 'vertical', + boxPlot: { style: { shaftShape: 'line', lineWidth: 2 } } + } + }], + records: [ + { group: 'A', region: 'North', category: 'Device', item: 'Type 1', + min: 4.72, q1: 9.73, median: 10.17, q3: 10.51, max: 11.64, outliers: [12.01, 12.02, 14.03] }, + { group: 'A', region: 'South', category: 'Device', item: 'Type 1', + min: 9.4, q1: 10.06, median: 10.75, q3: 11.56, max: 12.5 }, + { group: 'B', region: 'East', category: 'Device', item: 'Type 2', + min: 8.74, q1: 9.46, median: 10.35, q3: 10.94, max: 12.21 } + ], + indicatorsAsCol: false, defaultRowHeight: 200, defaultHeaderRowHeight: 30, + defaultColWidth: 280, defaultHeaderColWidth: [80, 'auto', 'auto'], + corner: { titleOnDimension: 'row', headerStyle: { autoWrapText: true, padding: 0 } } + }); + }, + async verify(page) { + // 断言 chart 单元格和分位值进入表格,画布有效性由通用检查完成。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('箱线图单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/circle-packing-hierarchy.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/circle-packing-hierarchy.mjs new file mode 100644 index 0000000000..86e7ba94f2 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/circle-packing-hierarchy.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 68cba2db5d163300b3f67f84 + * 验证目的:透视图中的 circlePacking 层级数据可绘制叶节点与父节点。 + * 改写:用固定的甲乙组和数值代替来源的大型分类数据。 + */ +export default { + mount(container) { + // 两层子组和四个叶节点足以显示圆形打包图的嵌套关系。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.width = '700px'; + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['bucket'], indicatorsAsCol: false, + indicators: [{ indicatorKey: 'name', title: 'Hierarchy', cellType: 'chart', chartModule: 'vchart', + style: { padding: 1 }, chartSpec: { + type: 'circlePacking', data: { id: 'data1' }, categoryField: 'name', valueField: 'value', + circlePacking: { style: { fillOpacity: datum => datum.isLeaf ? 0.75 : 0.25 } }, + layoutPadding: 5, label: { style: { fontSize: 10, visible: datum => datum.depth === 1 } }, + animation: false + } }], + records: [{ group: 'All', bucket: 'One', name: 'root', children: [ + { name: 'Group A', children: [{ name: 'A1', value: 8 }, { name: 'A2', value: 12 }] }, + { name: 'Group B', children: [{ name: 'B1', value: 10 }, { name: 'B2', value: 6 }] } + ] }], + defaultRowHeight: 250, defaultHeaderRowHeight: 40, defaultColWidth: 320, defaultHeaderColWidth: 90 + }); + }, + async verify(page) { + // 层级记录和图表单元格都必须存在,避免仅渲染表头。 + await page.evaluate(() => { + const table = window.__visualTable; + const chartCells = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') chartCells.push({ col, row }); + if (!chartCells.length || table.records[0]?.children?.length !== 2) + throw new Error('圆形打包图的层级记录或图表单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/combination-forecast.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/combination-forecast.mjs new file mode 100644 index 0000000000..9393a68cb3 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/combination-forecast.mjs @@ -0,0 +1,55 @@ +/** + * BugServer case IDs: 66bf0a981140a800e454d5dd + * 验证目的:两个指标各自组合历史柱、趋势线和预测柱,且尺度独立。 + * 改写:匿名化指标与数值,保留三条 series 对应的数据流及年份关系。 + */ +export default { + mount(container) { + // 每个指标使用独立的 common 图表配置,同时包含三种时间段的数据流。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + // 生成第二指标时只替换数据字段,图表组合结构保持一致。 + const indicator = (key, title) => ({ indicatorKey: key, title, cellType: 'chart', + chartModule: 'vchart', style: { padding: 1 }, chartSpec: { + type: 'common', series: [ + { id: key, type: 'bar', data: { id: key }, xField: 'year', yField: key, + barMinWidth: 1, barMaxWidth: 30 }, + { id: `trend_${key}`, type: 'line', data: { id: `trend_${key}` }, + xField: 'year', yField: `trend_${key}`, point: { visible: false }, + line: { style: { stroke: '#999', lineDash: [5], lineWidth: 2 } } }, + { id: `forecast_${key}`, type: 'bar', data: { id: `forecast_${key}` }, + xField: 'year', yField: `forecast_${key}`, + bar: { style: { fill: '#36a269' } } } + ], axes: [{ orient: 'left', min: 0, + seriesId: [key, `trend_${key}`, `forecast_${key}`] }] + } }); + const records = []; + // 固定的历史与预测数据使两个数量级都可稳定比较。 + for (let i = 0; i < 4; i++) { + const year = String(2020 + i); + records.push({ year, quantity: 60 + i * 15 }, { year, trend_quantity: 65 + i * 15 }, + { year, amount: 3600 + i * 800 }, { year, trend_amount: 3800 + i * 750 }); + } + for (let i = 0; i < 3; i++) { + const year = String(2024 + i); + records.push({ year, forecast_quantity: 115 + i * 5 }, + { year, forecast_amount: 5800 + i * 250 }); + } + return new window.VTable.PivotChart(container, { + rows: [], columns: [], indicatorsAsCol: false, records, + indicators: [indicator('quantity', 'Quantity'), indicator('amount', 'Amount')], + defaultRowHeight: 200, defaultColWidth: 400, defaultHeaderRowHeight: 50 + }); + }, + async verify(page) { + // 两个独立 chart 单元格都需要进入布局,避免只渲染单个指标。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('组合图指标未完整绘制'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/crosshair-linkage-hover.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/crosshair-linkage-hover.mjs new file mode 100644 index 0000000000..2edd2913df --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/crosshair-linkage-hover.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 6916c732711d9200a827cda3 + * 验证目的:两个透视图指标共享维度时,悬停可显示跨图表的准线与提示。 + * 改写:固定 A/B/C 维度和柱线两图,去除来源的大型多指标数据。 + */ +export default { + mount(container) { + // 两个独立图表指标在同一透视表中共用 period 维度。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '430px'; + window.__crosshairHoverCount = 0; + const table = new window.VTable.PivotChart(container, { + rows: [], columns: [], indicatorsAsCol: false, + records: [ + { period: 'A', amount: 10 }, { period: 'B', amount: 18 }, { period: 'C', amount: 13 }, + { period: 'A', rate: 4 }, { period: 'B', rate: 9 }, { period: 'C', rate: 6 } + ], + indicators: [ + { indicatorKey: 'amount', title: 'Amount', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'common', + series: [{ id: 'amount', type: 'bar', data: { id: 'amount' }, + xField: 'period', yField: 'amount' }], + crosshair: { xField: { visible: true } }, animation: false } }, + { indicatorKey: 'rate', title: 'Rate', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'common', + series: [{ id: 'rate', type: 'line', data: { id: 'rate' }, + xField: 'period', yField: 'rate', point: { visible: true } }], + crosshair: { xField: { visible: true } }, animation: false } } + ], + chartDimensionLinkage: { showTooltip: true }, + defaultRowHeight: 180, defaultColWidth: 560, + widthMode: 'autoWidth', heightMode: 'autoHeight' + }); + table.onVChartEvent('pointermove', () => { window.__crosshairHoverCount++; }); + return table; + }, + async exercise(page) { + // 鼠标进入首个图表的绘图区,停留后由截图保存准线与提示状态。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') { + const b = table.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 80, y: host.y + (b.y1 + b.y2) / 2 }; + } + throw new Error('联动图表单元格缺失'); + }); + await page.mouse.move(point.x - 20, point.y); + await page.mouse.move(point.x + 4, point.y, { steps: 8 }); + await page.waitForTimeout(150); + }, + async verify(page) { + // 图表应收到真实指针事件,避免将静态双图误作悬停覆盖。 + await page.evaluate(() => { + if (window.__crosshairHoverCount < 1) + throw new Error('图表未收到悬停事件'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/heatmap-two-indicators.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/heatmap-two-indicators.mjs new file mode 100644 index 0000000000..7109ea1eb8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/heatmap-two-indicators.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 68cb7de11cfd3a00b25a86ed, 68cb7f3a597cd100b2f74a00, 69899a7209038a005df130d0 + * 验证目的:两个独立记录流的热力图指标与反向颜色图例共同绘制。 + * 改写:三条来源源码完全相同,虽名称不同均为 heatmap;用固定通用字段替换展示文字。 + */ +export default { + mount(container) { + // 来源是两个 indicatorKey 分别绑定两个数据流;共用颜色域但 y 字段不同。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + const makeIndicator = (key, yField) => ({ indicatorKey: key, cellType: 'chart', chartModule: 'vchart', + style: { padding: [1, 1, 0, 1] }, chartSpec: { + type: 'heatmap', direction: 'vertical', xField: 'year', yField, seriesField: 'kind', + valueField: key, padding: 0, data: { id: key }, + axes: [{ type: 'band', orient: 'left', bandPadding: 0 }, + { type: 'band', orient: 'bottom', bandPadding: 0 }], + region: [{ clip: true }], background: 'transparent', + color: { type: 'linear', range: ['#C2CEFF', '#5766EC'], domain: [{ dataId: key, fields: ['colorValue'] }] }, + label: { visible: true, smartInvert: true }, + cell: { style: { shape: 'rect', stroke: '#ffffff', lineWidth: 1, + fill: { field: 'colorValue', scale: 'color' } } } + } }); + return new window.VTable.PivotChart(container, { + rows: [], columns: [], indicators: [makeIndicator('line1', 'salesLabel'), + makeIndicator('line2', 'profitLabel')], + records: { line1: [{ year: '2019', salesLabel: 'Sales', kind: 'sales', line1: 200000, colorValue: 200000 }, + { year: '2020', salesLabel: 'Sales', kind: 'sales', line1: 400000, colorValue: 400000 }], + line2: [{ year: '2019', profitLabel: 'Profit', kind: 'sales', line2: 10000, colorValue: 200000 }, + { year: '2020', profitLabel: 'Profit', kind: 'sales', line2: 20000, colorValue: 400000 }] }, + widthMode: 'adaptive', heightMode: 'adaptive', indicatorsAsCol: false, + legends: { visible: true, type: 'color', orient: 'right', position: 'start', + colors: ['#C2CEFF', '#5766EC'], value: [1000000, 200000], min: 1000000, max: 200000, maxWidth: '30%' } + }); + }, + async verify(page) { + // 两个指标都必须产出 chart 单元格,不能只展示图例。 + await page.evaluate(() => { + const table = window.__visualTable; + let count = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) if (table.getCellType(col, row) === 'chart') count++; + if (count < 2) throw new Error('双热力图指标缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-color.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-color.mjs new file mode 100644 index 0000000000..1388d516f5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-color.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 69290d62e84559005d355243 + * 验证目的:透视直方图按指定 ordinal 颜色域绘制含零值的多个区间。 + * 改写:用固定通用形状与区间数值代替来源数据,增加固定行维度保证图表可见,保留 bin 起止字段和颜色配置。 + */ +export default { + mount(container) { + // 两种形状分别落在独立图表单元格内,零值区间检验空柱绘制。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + const records = []; + // 每种形状都有相同 bin 边界,但各自数据量不同。 + for (const [shape, values] of [['Circle', [6, 2, 0, 4]], ['Square', [3, 0, 5, 1]]]) + values.forEach((value, index) => records.push({ group: 'All', shape, from: index + 1, + to: index + 2, value })); + return new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['shape'], + indicators: [{ indicatorKey: 'value', title: 'Value', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'histogram', xField: 'from', x2Field: 'to', + yField: 'value', seriesField: 'shape', data: { id: 'data1' }, barGap: 2, + color: { type: 'ordinal', domain: ['Circle', 'Square'], range: ['red', 'blue'] }, + legends: { visible: false } }, style: { padding: [1, 1, 0, 1] } }], + records, indicatorsAsCol: false, defaultRowHeight: 230, defaultColWidth: 290, + defaultHeaderRowHeight: 40, defaultHeaderColWidth: 80 + }); + }, + async verify(page) { + // 两组 bin 数据都需要成为 chart 单元格,颜色和空柱由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + const rect = table.getCellRect(2, 1).bounds; + if (charts < 2 || rect.x2 > 800 || rect.y2 > 400) + throw new Error(`直方图单元格未完整进入视口:${JSON.stringify(rect)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-overlap.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-overlap.mjs new file mode 100644 index 0000000000..67f4f6a14e --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/histogram-overlap.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 68cba1911ef44500a8bec33f + * 验证目的:透视直方图的多个系列存在重叠区间时,区间端点与指标仍被绘制。 + * 改写:来源的大量重复区间缩减到跨城市、跨类别的代表组合,并缩小标题尺寸让柱体进入截图。 + */ +export default { + mount(container) { + // 保留 0-100 与 50-150 的重叠,以及同区间不同系列。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + columns: ['category'], rows: ['city'], + indicators: [{ indicatorKey: 'profit', title: 'Value', cellType: 'chart', chartModule: 'vchart', + headerStyle: { color: 'red', borderLineWidth: [1, 0, 1, 0], autoWrapText: true }, + style: { padding: 1 }, chartSpec: { type: 'histogram', xField: 'from', x2Field: 'to', + yField: 'profit', seriesField: 'type', data: { id: 'data1' }, + bar: { style: { stroke: 'white', lineWidth: 1 } } } }], + records: [{ from: 0, to: 100, profit: 300, type: 'A', city: 'North', category: 'Device' }, + { from: 0, to: 100, profit: 100, type: 'B', city: 'North', category: 'Device' }, + { from: 50, to: 150, profit: 30, type: 'B', city: 'North', category: 'Device' }, + { from: 120, to: 130, profit: 150, type: 'D', city: 'North', category: 'Device' }, + { from: 10, to: 16, profit: 3, type: 'B', city: 'South', category: 'Office' }, + { from: 16, to: 18, profit: 15, type: 'C', city: 'South', category: 'Office' }], + indicatorsAsCol: false, defaultRowHeight: 200, defaultColWidth: 280, + defaultHeaderRowHeight: 40, defaultHeaderColWidth: 80 + }); + }, + async verify(page) { + // 两个透视分组都必须生成图表格。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('重叠区间直方图缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/mark-line.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/mark-line.mjs new file mode 100644 index 0000000000..c637d93028 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/mark-line.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 6614f1552acd9c00d1c98a65 + * 验证目的:透视柱状图同时绘制汇总标记线、百分比端点和起始三角符号。 + * 改写:数值与日期为固定示例,去除无关主题和远程 VChart 加载。 + */ +export default { + mount(container) { + // 本地 VChart bundle 使标记线与图表进入相同的视觉快照。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + rows: [], columns: [], indicatorsAsCol: false, + records: [ + { day: '2023-12-25', count: 6 }, { day: '2023-12-26', count: 59 }, + { day: '2023-12-28', count: 29 }, { day: '2023-12-29', count: 82 }, + { day: '2023-12-30', count: 107 } + ], + indicators: [{ indicatorKey: 'count', title: 'Count', cellType: 'chart', chartModule: 'vchart', + style: { padding: 1 }, chartSpec: { + type: 'common', + series: [{ id: 'count', type: 'bar', data: { id: 'count' }, xField: 'day', yField: 'count', + barMinWidth: 1, barMaxWidth: 30, barMinHeight: 1 }], + axes: [{ orient: 'left', min: 0, seriesId: ['count'] }], + markLine: [{ y1: 'sum', x: '2023-12-25', y: '10%', x1: '2023-12-30', + autoRange: true, relativeSeriesIndex: 0, + startSymbol: { visible: true, style: { symbolType: 'triangleDown', size: 8 } }, + endSymbol: { visible: false }, + line: { style: { stroke: '#000', lineDash: [5], lineWidth: 2 } }, + label: { visible: true, position: 'insideStartTop' } }] + } }], + defaultRowHeight: 200, defaultColWidth: 560, defaultHeaderRowHeight: 50, + widthMode: 'standard', heightMode: 'autoHeight' + }); + }, + async verify(page) { + // 柱状图单元格必须实际存在,标记线形状由快照比较。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 1) throw new Error('标记线图表单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs new file mode 100644 index 0000000000..8deaea1304 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 696dd1827a558400611ce035 + * 验证目的:透视饼图连续点击多个扇区时保留 element-select 多选状态。 + * 改写:将来源的区域和度量字段换成固定 A/B/C/D 类别与整数。 + */ +export default { + mount(container) { + // 多选交互通过图元状态改变透明度,最终状态由像素快照保存。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.width = '700px'; + container.style.height = '400px'; + window.__pieClicks = []; + const table = new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['bucket'], indicatorsAsCol: false, + indicators: [{ indicatorKey: 'value', title: 'Amount', cellType: 'chart', + chartModule: 'vchart', style: { padding: 1 }, chartSpec: { + type: 'pie', data: { id: 'data1' }, categoryField: 'category', valueField: 'value', + outerRadius: 0.8, innerRadius: 0, + pie: { state: { selected: { opacity: 1 }, selected_reverse: { opacity: 0.2 } } }, + interactions: [{ type: 'element-select', isMultiple: true, triggerOff: 'empty' }], + animation: false + } }], + records: [ + { group: 'All', bucket: 'One', category: 'A', value: 6 }, + { group: 'All', bucket: 'One', category: 'B', value: 9 }, + { group: 'All', bucket: 'One', category: 'C', value: 12 }, + { group: 'All', bucket: 'One', category: 'D', value: 8 } + ], + defaultRowHeight: 230, defaultColWidth: 290, + defaultHeaderRowHeight: 40, defaultHeaderColWidth: 80, + chartDimensionLinkage: { showTooltip: true } + }); + table.onVChartEvent('click', args => { window.__pieClicks.push(args?.datum?.category ?? 'chart'); }); + return table; + }, + async exercise(page) { + // 三次点击分别落在圆周不同象限,保留来源的连续选择动作。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const cell = Array.from({ length: table.rowCount }, (_, row) => + Array.from({ length: table.colCount }, (_, col) => ({ col, row }))) + .flat().find(({ col, row }) => table.getCellType(col, row) === 'chart'); + if (!cell) throw new Error('饼图单元格未渲染'); + const b = table.getCellRect(cell.col, cell.row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + const cx = host.x + (b.x1 + b.x2) / 2; + const cy = host.y + (b.y1 + b.y2) / 2; + return [{ x: cx + 70, y: cy }, { x: cx - 35, y: cy + 55 }, + { x: cx - 20, y: cy - 60 }]; + }); + for (const point of points) await page.mouse.click(point.x, point.y); + await page.mouse.move(650, 350); + }, + async verify(page) { + // 至少两个不同图元必须收到真实图表点击,避免点击到空白区域。 + await page.evaluate(() => { + if (new Set(window.__pieClicks).size < 2) + throw new Error(`饼图多选未点击不同扇区:${JSON.stringify(window.__pieClicks)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/scatter-axes.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/scatter-axes.mjs new file mode 100644 index 0000000000..91229d8e19 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/scatter-axes.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 6690fbcd49841700ac76649e + * 验证目的:同一透视图中 bar 和 scatter 指标各自绑定 seriesId 轴。 + * 改写:类别改为通用文字,保留两个不同量级数据流、左右轴配置与自动尺寸。 + */ +export default { + mount(container) { + // 分开两个记录流,确保 bar 与 scatter 不会错误共享数值轴。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + const chart = (key, type) => ({ indicatorKey: key, title: key, cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'common', series: [{ id: key, type, data: { id: key }, + xField: 'group', yField: key, ...(type === 'scatter' ? { point: { style: { size: 8 } } } : {}) }], + axes: [{ orient: 'left', min: 0, seriesId: [key] }, + { orient: 'right', visible: false, seriesId: [key] }] }, + style: { padding: 1 } }); + return new window.VTable.PivotChart(container, { + indicatorsAsCol: false, rows: [], columns: [], + records: [{ group: 'A', count: 11581 }, { group: 'B', count: 19173 }, + { group: 'C', count: 6780 }, { group: 'A', value: 681967.69 }, + { group: 'B', value: 1053092.69 }, { group: 'C', value: 412478.55 }], + indicators: [chart('count', 'bar'), chart('value', 'scatter')], + corner: { titleOnDimension: 'row', disableHeaderHover: true }, + widthMode: 'autoWidth', heightMode: 'autoHeight', defaultRowHeight: 200, + defaultHeaderRowHeight: 50, defaultColWidth: 280, defaultHeaderColWidth: 120, + autoFillWidth: true, autoFillHeight: true, tooltip: { confine: false }, + hover: { disableAxisHover: true } + }); + }, + async verify(page) { + // bar 和 scatter 均须成为真实的 chart 单元格。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('双轴散点透视图缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/sunburst-hierarchy.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/sunburst-hierarchy.mjs new file mode 100644 index 0000000000..0489f69f5d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/sunburst-hierarchy.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 68cba293e9f70b00b11e93d5 + * 验证目的:行列维度下的 sunburst 图表读取嵌套 children 数据并绘制层级扇区。 + * 改写:原有城市与类别改为通用分组,保留三层数据树。 + */ +export default { + mount(container) { + // 两个维度单元格各使用不同层级值,防止退化为单一扇区。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.height = '400px'; + return new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['category'], indicatorsAsCol: false, + indicators: [{ indicatorKey: 'name', title: 'Hierarchy', cellType: 'chart', chartModule: 'vchart', + style: { padding: 1 }, chartSpec: { type: 'sunburst', + categoryField: 'name', valueField: 'value', outerRadius: 1, innerRadius: 0, + data: { id: 'data1' } } }], + records: [ + { name: 'Collection A', group: 'Group A', category: 'Type 1', children: [ + { name: 'North', children: [{ name: 'One', value: 80 }, { name: 'Two', value: 120 }] }, + { name: 'South', children: [{ name: 'One', value: 60 }, { name: 'Two', value: 150 }] } + ] }, + { name: 'Collection B', group: 'Group B', category: 'Type 1', children: [ + { name: 'East', children: [{ name: 'One', value: 90 }, { name: 'Two', value: 75 }] }, + { name: 'West', children: [{ name: 'One', value: 55 }, { name: 'Two', value: 110 }] } + ] } + ], defaultRowHeight: 220, defaultColWidth: 280, defaultHeaderRowHeight: 35 + }); + }, + async verify(page) { + // 层级维度下必须有两个 chart 单元格;扇区层级由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 2) throw new Error('Sunburst 层级图表单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/aggregation-rules.mjs b/packages/vtable/__tests__/visual/cases/pivot/aggregation-rules.mjs new file mode 100644 index 0000000000..5999dd3f3c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/aggregation-rules.mjs @@ -0,0 +1,41 @@ +/** + * BugServer case IDs: 64ed9179d4858ce3fbd85ada + * 验证目的:同一个 sales 字段按 SUM、COUNT、AVG 三种聚合规则形成指标行。 + * 改写:使用通用数值和维度,保留三种 aggregationType 及独立数字格式。 + */ +export default { + mount(container) { + // 重复维度组合中的 10 和 20 应分别聚合为 30、2、15。 + const VTable = window.VTable; + return new VTable.PivotTable(container, { + rows: ['region', 'site'], columns: ['category', 'variant'], + indicators: ['Total', 'Count', 'Average'], enableDataAnalysis: true, + indicatorTitle: 'Metric', indicatorsAsCol: false, + dataConfig: { aggregationRules: [ + { indicatorKey: 'Total', field: 'sales', aggregationType: VTable.TYPES.AggregationType.SUM, + formatFun: VTable.DataStatistics.numberFormat({ suffix: ' units' }) }, + { indicatorKey: 'Count', field: 'sales', aggregationType: VTable.TYPES.AggregationType.COUNT, + formatFun: VTable.DataStatistics.numberFormat({ digitsAfterDecimal: 0, thousandsSep: '', suffix: ' items' }) }, + { indicatorKey: 'Average', field: 'sales', aggregationType: VTable.TYPES.AggregationType.AVG, + formatFun: VTable.DataStatistics.numberFormat({ suffix: ' units' }) } + ] }, + corner: { titleOnDimension: 'row' }, + records: [{ region: 'A', site: 'A1', category: 'X', variant: 'X1', sales: 10 }, + { region: 'A', site: 'A1', category: 'X', variant: 'X1', sales: 20 }, + { region: 'A', site: 'A2', category: 'X', variant: 'X1', sales: 40 }, + { region: 'B', site: 'B1', category: 'X', variant: 'X1', sales: 5 }], + widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 聚合后的三个结果都必须出现在实际单元格中。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(Number(table.getCellOriginValue(col, row))); + if (![30, 2, 15].every(value => values.includes(value))) + throw new Error(`SUM/COUNT/AVG 聚合结果缺失: ${JSON.stringify(values)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/analysis-two-level.mjs b/packages/vtable/__tests__/visual/cases/pivot/analysis-two-level.mjs new file mode 100644 index 0000000000..504657eb82 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/analysis-two-level.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 64ed8d04d4858ce3fbd85ad4 + * 验证目的:两级行列维度、两个指标与数据分析在透视表中共同生效。 + * 改写:将原例的地区销售明细换成固定的通用 A/B 数据,保留维度层级和指标结构。 + */ +export default { + mount(container) { + // 使用完整的两级交叉组合,避免缺失组合掩盖聚合错误。 + const records = [ + { group: 'A', item: 'A1', kind: 'X', variant: 'X1', amount: 10, count: 1 }, + { group: 'A', item: 'A2', kind: 'X', variant: 'X2', amount: 20, count: 2 }, + { group: 'B', item: 'B1', kind: 'Y', variant: 'Y1', amount: 30, count: 3 }, + { group: 'B', item: 'B2', kind: 'Y', variant: 'Y2', amount: 40, count: 4 } + ]; + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], + columns: ['kind', 'variant'], + indicators: ['amount', 'count'], + enableDataAnalysis: true, + indicatorTitle: 'Measure', + indicatorsAsCol: false, + corner: { titleOnDimension: 'row' }, + records, + widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 检查聚合后的数值确实进入可见单元格,并验证行列层级。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount < 4 || table.colCount < 4) throw new Error('透视维度未展开'); + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes(10) || !values.includes(40)) throw new Error('透视聚合值缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/calculated-field-hidden-dependencies.mjs b/packages/vtable/__tests__/visual/cases/pivot/calculated-field-hidden-dependencies.mjs new file mode 100644 index 0000000000..3c2cab6df8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/calculated-field-hidden-dependencies.mjs @@ -0,0 +1,39 @@ +/** + * BugServer case IDs: 667283a571989000cfc6dc95 + * 验证目的:计算字段可引用未列为显示指标的两个原始字段。 + * 改写:将地区明细缩成固定通用维度,保留 sales/number 的除法和行列合计。 + */ +export default { + mount(container) { + // 显示列表只有计算指标,依赖字段仍留在原始记录中。 + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['kind', 'variant'], + indicators: [{ indicatorKey: 'unitPrice', title: 'Unit price', format: value => '$' + Number(value).toFixed(2) }], + enableDataAnalysis: true, indicatorTitle: 'Measure', indicatorsAsCol: false, + dataConfig: { + calculatedFieldRules: [{ key: 'unitPrice', dependIndicatorKeys: ['sales', 'number'], + calculateFun: value => value.sales / value.number }], + totals: { row: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['group'], + grandTotalLabel: 'Total', subTotalLabel: 'Subtotal' }, + column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['kind'], + grandTotalLabel: 'Total', subTotalLabel: 'Subtotal' } } + }, + corner: { titleOnDimension: 'row' }, + records: [{ group: 'A', item: 'A1', kind: 'X', variant: 'X1', sales: 10, number: 2 }, + { group: 'A', item: 'A2', kind: 'X', variant: 'X2', sales: 30, number: 3 }, + { group: 'B', item: 'B1', kind: 'Y', variant: 'Y1', sales: 12, number: 4 }], + widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 必须读到至少一个算出的 5 和 10,避免只验证配置存在。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(Number(table.getCellOriginValue(col, row))); + if (!values.some(value => Math.abs(value - 5) < 1e-9) || !values.some(value => Math.abs(value - 10) < 1e-9)) + throw new Error('隐藏依赖字段的计算结果缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/column-header-title.mjs b/packages/vtable/__tests__/visual/cases/pivot/column-header-title.mjs new file mode 100644 index 0000000000..d41e2c2dbf --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/column-header-title.mjs @@ -0,0 +1,52 @@ +/** + * BugServer case IDs: 6474534d5d221c008666ee18 + * 验证目的:columnHeaderTitle 在列维度上方增加独立标题行。 + * 改写:将来源的大型主题和数据矩阵缩为固定匿名记录,对照无标题配置。 + */ +export default { + mount(container) { + // 两张透视表共享记录,仅切换 columnHeaderTitle 以隔离标题行效果。 + container.style.width = '800px'; + container.style.height = '330px'; + container.style.display = 'grid'; + container.style.gridTemplateColumns = '1fr 1fr'; + const records = [ + { group: 'A', period: 'First', amount: 10 }, + { group: 'A', period: 'Second', amount: 20 }, + { group: 'B', period: 'First', amount: 30 } + ]; + const tables = [false, true].map(withTitle => { + const host = document.createElement('div'); + host.style.cssText = 'width:390px;height:320px'; + container.append(host); + return new window.VTable.PivotTable(host, { + rows: [{ dimensionKey: 'group', title: 'Group' }], + columns: [{ dimensionKey: 'period', title: 'Period' }], + indicators: [{ indicatorKey: 'amount', title: 'Amount' }], + records, + ...(withTitle ? { columnHeaderTitle: { title: 'Periods', headerStyle: { textAlign: 'center' } } } : {}), + widthMode: 'standard' + }); + }); + return { + tables, + async renderAsync() { + // 等待两张画布都完成绘制后再截图。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 用例结束时释放两张透视表。 + tables.forEach(table => table.release()); + } + }; + }, + async verify(page) { + // 标题配置应比对照表多一层列头,且两张表都具有真实画布。 + await page.evaluate(() => { + const [plain, titled] = window.__visualTable.tables; + if (titled.columnHeaderLevelCount !== plain.columnHeaderLevelCount + 1 || + !plain.canvas?.width || !titled.canvas?.width) + throw new Error('列头标题未增加独立表头层'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/corner-empty-matrix.mjs b/packages/vtable/__tests__/visual/cases/pivot/corner-empty-matrix.mjs new file mode 100644 index 0000000000..a68a77e133 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/corner-empty-matrix.mjs @@ -0,0 +1,69 @@ +/** + * BugServer case IDs: 67eb9a84fddcfa00a827d1e5, 67eb9aad731cd600a72b8541, 67eb9b1d2b0c7600a7633c83, 67eb9b4ab8637b00a7a32276, 67eb9baddc8abb00a7c081f1, 67eb9bcdd3963500b3ec8261 + * 验证目的:无行、无列与无指标的角头组合均可实际绘制。 + * 改写:六个相邻 BugServer 配置共享匿名二维数据,在一张快照中并排检查。 + */ +export default { + mount(container) { + // 各子表仍由真正的 PivotTable 绘制,共享的仅是无业务含义的输入记录。 + container.style.width = '800px'; + container.style.height = '640px'; + container.style.display = 'grid'; + container.style.gridTemplateColumns = '1fr 1fr'; + container.style.gridTemplateRows = 'repeat(3, 210px)'; + const records = [ + { region: 'A', item: 'X', type: 'T1', subtype: 'S1', amount: 5 }, + { region: 'A', item: 'Y', type: 'T1', subtype: 'S2', amount: 7 }, + { region: 'B', item: 'Z', type: 'T2', subtype: 'S1', amount: 12 } + ]; + const variants = [ + { label: 'no rows / no columns / indicator column', indicatorsAsCol: true, + corner: { titleOnDimension: 'none', forceShowHeader: true } }, + { label: 'no rows / no columns / indicator row', indicatorsAsCol: false, + corner: { titleOnDimension: 'none', forceShowHeader: true } }, + { label: 'columns only', columns: ['type', 'subtype'], indicatorsAsCol: false, + corner: { titleOnDimension: 'column', forceShowHeader: true } }, + { label: 'rows only', rows: ['region', 'item'], indicatorsAsCol: true, + corner: { titleOnDimension: 'row', forceShowHeader: true } }, + { label: 'rows / no indicator', rows: ['region', 'item'], indicators: [], + corner: { titleOnDimension: 'row', forceShowHeader: true } }, + { label: 'columns / no indicator', columns: ['type', 'subtype'], indicators: [], + corner: { titleOnDimension: 'column', forceShowHeader: true } } + ]; + const tables = variants.map(variant => { + const panel = document.createElement('div'); + panel.style.cssText = 'height:205px;overflow:hidden;border:1px solid #bbb'; + const label = document.createElement('div'); + label.textContent = variant.label; + label.style.cssText = 'height:22px;font:12px sans-serif'; + const host = document.createElement('div'); + host.style.cssText = 'width:100%;height:180px'; + panel.append(label, host); + container.append(panel); + const { label: ignored, ...options } = variant; + return new window.VTable.PivotTable(host, { + records, indicators: ['amount'], widthMode: 'standard', ...options + }); + }); + return { + tables, + async renderAsync() { + // 等待六张子表都完成绘制后再进入截图阶段。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 用例结束时逐个释放子表,避免多实例残留。 + tables.forEach(table => table.release()); + } + }; + }, + async verify(page) { + // 六种配置均须有可见行列与实际画布,避免仅有外层标签通过截图。 + await page.evaluate(() => { + const tables = window.__visualTable.tables; + if (tables.length !== 6 || tables.some(table => table.rowCount < 1 || table.colCount < 1 || + !table.canvas?.width || !table.canvas?.height)) + throw new Error('空维度矩阵有未绘制的透视表'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/corner-remaining-variants.mjs b/packages/vtable/__tests__/visual/cases/pivot/corner-remaining-variants.mjs new file mode 100644 index 0000000000..713ca04474 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/corner-remaining-variants.mjs @@ -0,0 +1,53 @@ +/** + * BugServer case IDs: 67eba18063ae2300a3122147, 67eba1e52ef4e200a7775a9c, 67ecf4e1d4307700b694535e + * 验证目的:角头在只有行维度、只有列维度和无指标的其余排列中仍能绘制。 + * 改写:来源的地区与商品明细统一替换为 A/B、X/Y 匿名组合。 + */ +export default { + mount(container) { + // 三张表分别覆盖指标在行、指标在列及无指标且只有一级行维度。 + container.style.width = '800px'; + container.style.height = '660px'; + container.style.display = 'grid'; + container.style.gridTemplateRows = 'repeat(3, 220px)'; + const records = [ + { group: 'A', item: 'A1', type: 'X', subtype: 'X1', amount: 10 }, + { group: 'A', item: 'A2', type: 'X', subtype: 'X2', amount: 20 }, + { group: 'B', item: 'B1', type: 'Y', subtype: 'Y1', amount: 30 } + ]; + const variants = [ + { rows: ['group', 'item'], indicators: ['amount'], indicatorsAsCol: false, + corner: { titleOnDimension: 'row', forceShowHeader: true } }, + { columns: ['type', 'subtype'], indicators: ['amount'], indicatorsAsCol: true, + corner: { titleOnDimension: 'column', forceShowHeader: true } }, + { rows: ['group'], indicators: [], indicatorsAsCol: true, + corner: { titleOnDimension: 'row', forceShowHeader: true } } + ]; + const tables = variants.map(variant => { + const host = document.createElement('div'); + host.style.cssText = 'width:780px;height:210px'; + container.append(host); + return new window.VTable.PivotTable(host, { records, ...variant, widthMode: 'standard' }); + }); + return { + tables, + async renderAsync() { + // 等待三个布局各自完成绘制。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 测试结束后释放全部透视表。 + tables.forEach(table => table.release()); + } + }; + }, + async verify(page) { + // 三种空维度排列均须生成有效行列和画布。 + await page.evaluate(() => { + const tables = window.__visualTable.tables; + if (tables.length !== 3 || tables.some(table => + table.rowCount < 1 || table.colCount < 1 || !table.canvas?.width)) + throw new Error('角头补充排列存在未绘制表格'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/corner-sort-one-dimension.mjs b/packages/vtable/__tests__/visual/cases/pivot/corner-sort-one-dimension.mjs new file mode 100644 index 0000000000..4e772d8217 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/corner-sort-one-dimension.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 69d5d35be48f3a005ed8b838 + * 验证目的:角头启用排序图标时,透视排序状态可指向单级角头维度。 + * 改写:使用固定 A/B 分类与整数指标,保留 showSortInCorner 和 isPivotCorner 路径。 + */ +export default { + mount(container) { + // 两级行维度与单级列维度共同显示角头排序状态及两个数值指标。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.PivotTable(container, { + records: [ + { category: 'A', item: 'A1', sales: 100, profit: 10 }, + { category: 'A', item: 'A2', sales: 150, profit: 15 }, + { category: 'B', item: 'B1', sales: 200, profit: 20 }, + { category: 'B', item: 'B2', sales: 250, profit: 25 } + ], + rows: [ + { dimensionKey: 'item', title: 'Item', showSortInCorner: true }, + { dimensionKey: 'category', title: 'Category', showSortInCorner: true } + ], + columns: [{ dimensionKey: 'category', title: 'Category', showSortInCorner: true }], + indicators: [ + { indicatorKey: 'sales', title: 'Sales', showSortInCorner: true }, + { indicatorKey: 'profit', title: 'Profit', showSortInCorner: true } + ], + corner: { titleOnDimension: 'all' }, + pivotSortState: [{ dimensions: [{ dimensionKey: 'category', isPivotCorner: true }], order: 'desc' }] + }); + }, + async verify(page) { + // 角头排序路径和指标值都应被实际透视表接收并绘制。 + await page.evaluate(() => { + const table = window.__visualTable; + const state = table.pivotSortState?.[0]; + if (state?.order !== 'desc' || state.dimensions?.length !== 1 || + state.dimensions.some(d => !d.isPivotCorner) || table.rowCount < 3) + throw new Error(`角头排序状态缺失:${JSON.stringify(table.pivotSortState)}`); + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes(100) || !values.includes(250)) throw new Error('角头排序的指标数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/corner-sort-two-dimensions.mjs b/packages/vtable/__tests__/visual/cases/pivot/corner-sort-two-dimensions.mjs new file mode 100644 index 0000000000..8b76473a50 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/corner-sort-two-dimensions.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 69d5d380361ead005d3155e3 + * 验证目的:角头启用排序图标时,透视排序状态可指向两级角头维度。 + * 改写:使用固定 A/B 分类与整数指标,保留 showSortInCorner 和 isPivotCorner 路径。 + */ +export default { + mount(container) { + // 两级行维度与单级列维度共同显示角头排序状态及两个数值指标。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.PivotTable(container, { + records: [ + { category: 'A', item: 'A1', sales: 100, profit: 10 }, + { category: 'A', item: 'A2', sales: 150, profit: 15 }, + { category: 'B', item: 'B1', sales: 200, profit: 20 }, + { category: 'B', item: 'B2', sales: 250, profit: 25 } + ], + rows: [ + { dimensionKey: 'item', title: 'Item', showSortInCorner: true }, + { dimensionKey: 'category', title: 'Category', showSortInCorner: true } + ], + columns: [{ dimensionKey: 'category', title: 'Category', showSortInCorner: true }], + indicators: [ + { indicatorKey: 'sales', title: 'Sales', showSortInCorner: true }, + { indicatorKey: 'profit', title: 'Profit', showSortInCorner: true } + ], + corner: { titleOnDimension: 'all' }, + pivotSortState: [{ dimensions: [{ dimensionKey: 'item', isPivotCorner: true }, + { dimensionKey: 'category', isPivotCorner: true }], order: 'desc' }] + }); + }, + async verify(page) { + // 角头排序路径和指标值都应被实际透视表接收并绘制。 + await page.evaluate(() => { + const table = window.__visualTable; + const state = table.pivotSortState?.[0]; + if (state?.order !== 'desc' || state.dimensions?.length !== 2 || + state.dimensions.some(d => !d.isPivotCorner) || table.rowCount < 3) + throw new Error(`角头排序状态缺失:${JSON.stringify(table.pivotSortState)}`); + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes(100) || !values.includes(250)) throw new Error('角头排序的指标数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/corner-without-rows.mjs b/packages/vtable/__tests__/visual/cases/pivot/corner-without-rows.mjs new file mode 100644 index 0000000000..efa7888478 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/corner-without-rows.mjs @@ -0,0 +1,34 @@ +/** + * BugServer case IDs: 66b32ebbd62b6300ba4721d8 + * 验证目的:没有行维度与指标时,显式 columnTree 仍显示列头和强制角头。 + * 改写:删除未触发的菜单和粘贴配置,保留无行无指标的结构边界。 + */ +export default { + mount(container) { + // 三个固定列树节点足以验证强制角头与列头布局。 + return new window.VTable.PivotTable(container, { + defaultColWidth: 200, + columnTree: [ + { dimensionKey: 'Category', value: 'Office Supplies' }, + { dimensionKey: 'Category', value: 'Technology' }, + { dimensionKey: 'Category', value: 'Furniture' } + ], + columns: [{ dimensionKey: 'City', title: 'City', + headerStyle: { textStick: true, bgColor: '#356b9c', color: '#00ffff' } }], + indicatorsAsCol: true, + corner: { forceShowHeader: true, titleOnDimension: 'column', + headerStyle: { bgColor: '#356b9c', color: '#00ffff' } } + }); + }, + async verify(page) { + // 三个类别必须真的成为表格头部,而不是仅存在配置中。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellValue(col, row)); + if (!values.includes('Technology') || !values.includes('Furniture')) + throw new Error('空行维度列头缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/custom-merge-subtotal.mjs b/packages/vtable/__tests__/visual/cases/pivot/custom-merge-subtotal.mjs new file mode 100644 index 0000000000..d94cc2fe99 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/custom-merge-subtotal.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 6785dfb8d2dacd00b3443ebf + * 验证目的:行头自定义合并两列时,小计和总计单元格保留原始聚合值。 + * 改写:将地区名称改为通用组,保留三维行头、跳过合计的合并回调与行小计。 + */ +export default { + mount(container) { + // 普通行合并第 1-2 列,小计/总计返回 undefined 交回透视表处理。 + return new window.VTable.PivotTable(container, { + records: [{ area: 'North', region: 'N1', city: 'N1', amount: 1 }, + { area: 'North', region: 'N2', city: 'N2', amount: 2 }, + { area: 'South', region: 'S1', city: 'S1', amount: 3 }], + rows: [{ dimensionKey: 'area', title: 'Area' }, { dimensionKey: 'region', title: 'Region' }, + { dimensionKey: 'city', title: 'City' }], + indicators: [{ indicatorKey: 'amount', title: 'Amount', width: 100 }], + dataConfig: { totals: { row: { showGrandTotals: true, showSubTotals: true, + subTotalsDimensions: ['area'], grandTotalLabel: 'Total', subTotalLabel: 'Subtotal' } } }, + customMergeCell: (col, row, table) => { + if (col <= 0 || col >= 3 || row <= 0) return undefined; + const value = table.getCellOriginValue(col, row); + if (value === 'Subtotal' || value === 'Total') return undefined; + return { text: value, range: { start: { col: 1, row }, end: { col: 2, row } }, + style: { textAlign: 'center' } }; + }, + keyboardOptions: { moveEditCellOnArrowKeys: true, copySelected: true, pasteValueToCell: true } + }); + }, + async verify(page) { + // North 小计 3 与总计 6 必须保留,且至少有一个普通行头合并。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes('Subtotal') || !values.includes(6)) throw new Error('自定义合并丢失合计'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/custom-total-data-tree.mjs b/packages/vtable/__tests__/visual/cases/pivot/custom-total-data-tree.mjs new file mode 100644 index 0000000000..36a441f2c8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/custom-total-data-tree.mjs @@ -0,0 +1,56 @@ +/** + * BugServer case IDs: 652e02311dd15a4ab522f753 + * 验证目的:带显式行列汇总记录的树形透视表仍能展开并显示汇总值。 + * 改写:原地区商品明细换成固定 A/B 分类,保留缺维度汇总行和树展开动作。 + */ +export default { + mount(container) { + // 缺失部分维度的记录代表外部传入的小计和总计。 + container.style.height = '400px'; + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['type', 'subtype'], + indicators: ['amount', 'count'], indicatorsAsCol: true, + enableDataAnalysis: true, rowHierarchyType: 'tree', rowExpandLevel: 1, + dataConfig: { totals: { + row: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['group', 'item'] }, + column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['type'] } + } }, + records: [ + { amount: 111, count: 10 }, + { group: 'A', amount: 55, count: 5 }, + { group: 'A', type: 'X', amount: 30, count: 3 }, + { type: 'X', subtype: 'X1', amount: 45, count: 4 }, + { group: 'A', item: 'A1', type: 'X', subtype: 'X1', amount: 12, count: 1 }, + { group: 'A', item: 'A2', type: 'X', subtype: 'X1', amount: 18, count: 2 }, + { group: 'B', item: 'B1', type: 'Y', subtype: 'Y1', amount: 25, count: 3 } + ], widthMode: 'standard' + }); + }, + async exercise(page) { + // 定位 A 行的树图标并展开子项。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const row = Array.from({ length: table.rowCount }, (_, i) => i) + .find(i => table.getCellValue(0, i) === 'A'); + if (row === undefined || table.getHierarchyState(0, row) !== 'collapse') + throw new Error('A 组不是可展开树节点'); + const b = table.getCellRect(0, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 23, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // A 组展开且显式总计 111 进入可见透视值。 + await page.evaluate(() => { + const table = window.__visualTable; + const row = Array.from({ length: table.rowCount }, (_, i) => i) + .find(i => table.getCellValue(0, i) === 'A'); + const values = []; + for (let y = 0; y < table.rowCount; y++) + for (let x = 0; x < table.colCount; x++) values.push(table.getCellOriginValue(x, y)); + if (row === undefined || table.getHierarchyState(0, row) !== 'expand' || !values.includes(111)) + throw new Error('树形小计展开或显式总计缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/empty-string-dimension.mjs b/packages/vtable/__tests__/visual/cases/pivot/empty-string-dimension.mjs new file mode 100644 index 0000000000..a8b28d05c0 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/empty-string-dimension.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 6971d76ed74ba0005dc5e9b6 + * 验证目的:空字符串列维度应与普通列维度并存,并显示 NONE 聚合值。 + * 改写:来源中的不透明字段与人口数据换成固定代号和数值字符串。 + */ +export default { + mount(container) { + // 同一期同时存在空维度和 A 维度,另附缺行维度的汇总记录。 + return new window.VTable.PivotTable(container, { + rows: [{ dimensionKey: 'period', title: 'Period', width: 120 }], + columns: [{ dimensionKey: 'segment', title: 'Segment', width: 130 }], + indicators: [{ indicatorKey: 'amount', title: 'Amount', width: 120 }], + records: [ + { period: 'P1', segment: '', amount: '10' }, + { period: 'P1', segment: 'A', amount: '20' }, + { period: 'P2', segment: '', amount: '30' }, + { period: 'P2', segment: 'A', amount: '40' }, + { segment: '', amount: '40' }, + { segment: 'A', amount: '60' } + ], + dataConfig: { aggregationRules: [{ indicatorKey: 'amount', field: 'amount', aggregationType: 'NONE' }], + totals: { row: { showGrandTotals: false }, column: { showGrandTotals: false } } }, + corner: { titleOnDimension: 'all' }, widthMode: 'standard' + }); + }, + async verify(page) { + // 空维度不能吞掉两期数值,也不能与 A 列合并。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(String(table.getCellOriginValue(col, row))); + if (table.colCount < 3 || !values.includes('10') || !values.includes('30') || + !values.includes('20') || !values.includes('40')) + throw new Error(`空字符串维度被合并或丢失:${JSON.stringify(values)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-rule.mjs b/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-rule.mjs new file mode 100644 index 0000000000..168fb4933a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-rule.mjs @@ -0,0 +1,30 @@ +/** + * BugServer case IDs: 64ed9123d4858ce3fbd85ad9 + * 验证目的:透视表按指定指标和列维度路径对行维度降序排序,并映射背景色。 + * 改写:销售明细换成固定 A/B/C 数值,保留 sortByIndicator、query 与 mappingRules。 + */ +export default { + mount(container) { + // 三个城市的 amount 分别为 10、30、20,降序应先 C 再 B 再 A。 + return new window.VTable.PivotTable(container, { + rows: ['region', 'city'], columns: ['kind', 'variant'], indicators: ['amount', 'count'], + enableDataAnalysis: true, indicatorsAsCol: false, + dataConfig: { sortRules: [{ sortField: 'city', sortByIndicator: 'amount', + sortType: window.VTable.TYPES.SortType.DESC, query: ['X', 'X1'] }], + mappingRules: [{ bgColor: { indicatorKey: 'amount', mapping: ({ value }) => value >= 20 ? '#ffc0c0' : '#ffffff' } }] }, + records: [{ region: 'R', city: 'A', kind: 'X', variant: 'X1', amount: 10, count: 1 }, + { region: 'R', city: 'C', kind: 'X', variant: 'X1', amount: 30, count: 3 }, + { region: 'R', city: 'B', kind: 'X', variant: 'X1', amount: 20, count: 2 }] + }); + }, + async verify(page) { + // 扫描行标题顺序,避免只确认规则被保存却未实际排序。 + await page.evaluate(() => { + const table = window.__visualTable; + const labels = Array.from({ length: table.rowCount }, (_, row) => table.getCellValue(1, row)); + const positions = ['C', 'B', 'A'].map(value => labels.indexOf(value)); + if (positions.some(index => index < 0) || !(positions[0] < positions[1] && positions[1] < positions[2])) + throw new Error(`透视指标排序错误:${labels}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-subtotal.mjs b/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-subtotal.mjs new file mode 100644 index 0000000000..7d2f56f101 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/indicator-sort-subtotal.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 65be028bce3320008eecf685 + * 验证目的:按指定指标和列路径排序行维度,同时显示该维度的小计。 + * 改写:维度标签改为通用名称,保留两级行列、两指标、query、sortRules 与 subTotalsDimensions。 + */ +export default { + mount(container) { + // 同一查询路径中给多个区域不同数值,以展示排序与小计。 + return new window.VTable.PivotTable(container, { + rows: ['region', 'site'], columns: ['category', 'variant'], + indicators: ['sales', 'number'], enableDataAnalysis: true, + indicatorsAsCol: true, indicatorTitle: 'Metric', + dataConfig: { sortRules: [{ sortField: 'region', sortByIndicator: 'sales', + sortType: window.VTable.TYPES.SortType.ASC, query: ['Type A', 'Variant X'] }], + totals: { row: { subTotalsDimensions: ['region'] } } }, + corner: { titleOnDimension: 'row' }, + records: [{ sales: 1295, number: 43, region: 'Region A', site: 'Site 1', category: 'Type A', variant: 'Variant X' }, + { sales: 995, number: 53, region: 'Region A', site: 'Site 2', category: 'Type A', variant: 'Variant X' }, + { sales: 1045, number: 33, region: 'Region A', site: 'Site 3', category: 'Type A', variant: 'Variant X' }, + { sales: 792, number: 14, region: 'Region B', site: 'Site 4', category: 'Type A', variant: 'Variant X' }, + { sales: 800, number: 24, region: 'Region C', site: 'Site 5', category: 'Type A', variant: 'Variant X' }], + widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 三个区域和指标小计应使透视行数大于原始五条记录。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount < 8 || table.colCount < 3 || !table.options.dataConfig.totals.row.subTotalsDimensions.includes('region')) + throw new Error('指标排序与小计场景未建立'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/initial-column-sort-state.mjs b/packages/vtable/__tests__/visual/cases/pivot/initial-column-sort-state.mjs new file mode 100644 index 0000000000..1de71a6bce --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/initial-column-sort-state.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 64bdfdee5134109a76ccddd5 + * 验证目的:透视列树指定分支的初始 pivotSortState 与自动填宽共同绘制。 + * 改写:保留非角头两级列路径、降序状态及 autoFillWidth,使用固定通用维度与记录。 + */ +export default { + mount(container) { + // 两级列树包含排序目标 Second 分支,并由固定记录提供可见指标值。 + return new window.VTable.PivotTable(container, { + rows: [{ dimensionKey: 'category', title: 'Category' }], + columns: [{ dimensionKey: 'region', title: 'Region' }, + { dimensionKey: 'method', title: 'Method', showSort: true }], + indicators: [{ indicatorKey: 'amount', title: 'Amount', showSort: true }], + columnTree: [{ dimensionKey: 'region', value: 'North', children: [ + { dimensionKey: 'method', value: 'First', children: [{ indicatorKey: 'amount' }] }, + { dimensionKey: 'method', value: 'Second', children: [{ indicatorKey: 'amount' }] } + ] }], + records: [ + { category: 'A', region: 'North', method: 'First', amount: 10 }, + { category: 'A', region: 'North', method: 'Second', amount: 20 }, + { category: 'B', region: 'North', method: 'First', amount: 30 }, + { category: 'B', region: 'North', method: 'Second', amount: 40 } + ], + pivotSortState: [{ dimensions: [ + { dimensionKey: 'region', value: 'North', isPivotCorner: false }, + { dimensionKey: 'method', value: 'Second', isPivotCorner: false } + ], order: 'desc' }], + enableDataAnalysis: true, autoFillWidth: true, widthMode: 'standard', + defaultHeaderRowHeight: 40, defaultHeaderColWidth: 90 + }); + }, + async verify(page) { + // 初始排序路径、列树和数据值都应被透视表接受。 + await page.evaluate(() => { + const table = window.__visualTable; + const state = table.pivotSortState?.[0]; + if (state?.order !== 'desc' || state.dimensions?.[1]?.value !== 'Second' || table.colCount < 3) + throw new Error(`初始透视排序状态缺失:${JSON.stringify(table.pivotSortState)}`); + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes(20) || !values.includes(40)) throw new Error('列树排序目标的指标数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/no-indicators.mjs b/packages/vtable/__tests__/visual/cases/pivot/no-indicators.mjs new file mode 100644 index 0000000000..1257c631ec --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/no-indicators.mjs @@ -0,0 +1,28 @@ +/** + * BugServer case IDs: 647452cf5d221c008666ee17 + * 验证目的:无指标透视表按显式行列树绘制链接型维度表头。 + * 改写:来源的大型主题与超长分类列表缩为固定公开样本,保留无指标、树和链接表头条件。 + */ +export default { + mount(container) { + // 显式树节点与零指标一起覆盖只有维度的透视边界。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.PivotTable(container, { + rows: [{ dimensionKey: 'group', title: 'Group', width: 'auto', headerType: 'link', linkDetect: true, linkJump: false }], + columns: [{ dimensionKey: 'method', title: 'Method', headerType: 'link', linkDetect: true, linkJump: false }], + rowTree: ['Alpha', 'Beta', 'Gamma', 'Delta'].map(value => ({ dimensionKey: 'group', value })), + columnTree: ['Standard', 'Express', 'Same day'].map(value => ({ dimensionKey: 'method', value })), + hideIndicatorName: true, allowFrozenColCount: 2, columnResizeType: 'indicator', + corner: { titleOnDimension: 'row', headerStyle: { textStick: true } } + }); + }, + async verify(page) { + // 行列树必须生成有效区域;视觉比较负责验证表头的绘制。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount < 4 || table.colCount < 3 || !Number.isFinite(table.getCellRect(1, 1)?.bounds?.x1)) + throw new Error('无指标透视表未生成预期的行列结构'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-group.mjs b/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-group.mjs new file mode 100644 index 0000000000..78e582bf53 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-group.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 662e20c6d4511700f6885626 + * 验证目的:indicatorGroup 拖动一个指标行边界时按比例调整同组的两个指标行。 + * 改写:来源的地区商品数据改为三个匿名行维度组合。 + */ +export default { + mount(container) { + // 每个条目有金额和数量两个指标行,拖动组边界应影响两行。 + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['period'], + indicators: ['amount', 'count'], indicatorsAsCol: false, + records: [ + { group: 'A', item: 'A1', period: 'First', amount: 10, count: 1 }, + { group: 'A', item: 'A2', period: 'First', amount: 20, count: 2 }, + { group: 'B', item: 'B1', period: 'Second', amount: 30, count: 3 } + ], + defaultRowHeight: 32, resize: { rowResizeMode: 'all', rowResizeType: 'indicatorGroup' } + }); + }, + async exercise(page) { + // 在第一个条目的指标行下边界拖动,并记录同组两行原始高度。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const row = table.columnHeaderLevelCount; + const b = table.getCellRect(table.rowHeaderLevelCount - 1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__indicatorGroupStartRow = row; + window.__indicatorGroupBefore = [table.getRowHeight(row), table.getRowHeight(row + 1)]; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + b.y2 + 1 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.down(); + await page.mouse.move(point.x, point.y + 36, { steps: 10 }); + await page.mouse.up(); + }, + async verify(page) { + // 同一指标组的两行都应增高,区别于单行调整。 + await page.evaluate(() => { + const table = window.__visualTable; + const row = window.__indicatorGroupStartRow; + const heights = [table.getRowHeight(row), table.getRowHeight(row + 1)]; + if (heights.some((height, index) => height < window.__indicatorGroupBefore[index] + 5)) + throw new Error(`指标组行高未同时改变:${JSON.stringify(heights)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-row.mjs b/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-row.mjs new file mode 100644 index 0000000000..eb494ce5ae --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/resize-indicator-row.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 662e204dd4511700f6885624 + * 验证目的:指标放在行上的透视表可拖动行头边界调整指标行高。 + * 改写:维度和数值换成固定匿名示例,保留 indicatorsAsCol=false 与拖拽。 + */ +export default { + mount(container) { + // 两个指标在每个行维度下形成可调整的指标行。 + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['region'], + indicators: ['amount', 'count'], indicatorsAsCol: false, + records: [ + { group: 'A', item: 'A1', region: 'East', amount: 10, count: 1 }, + { group: 'A', item: 'A2', region: 'West', amount: 20, count: 2 }, + { group: 'B', item: 'B1', region: 'East', amount: 30, count: 3 } + ], defaultRowHeight: 32, widthMode: 'standard', resize: { rowResizeMode: 'all' } + }); + }, + async exercise(page) { + // 在首个指标行的左侧行头边界向下拖动。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const row = table.columnHeaderLevelCount; + const b = table.getCellRect(table.rowHeaderLevelCount - 1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__pivotResizeRow = row; + window.__pivotResizeCol = table.rowHeaderLevelCount - 1; + window.__pivotHeightBefore = b.y2 - b.y1; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + b.y2 + 1 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.down(); + await page.mouse.move(point.x, point.y + 30, { steps: 10 }); + await page.mouse.up(); + }, + async verify(page) { + // 指标行相对矩形应比初始配置高至少 15px。 + await page.evaluate(() => { + const b = window.__visualTable.getCellRect(window.__pivotResizeCol, window.__pivotResizeRow).bounds; + if (b.y2 - b.y1 < window.__pivotHeightBefore + 15) + throw new Error('透视指标行高未调整'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/tree-zero-expand.mjs b/packages/vtable/__tests__/visual/cases/pivot/tree-zero-expand.mjs new file mode 100644 index 0000000000..d620c4f008 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/tree-zero-expand.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 66deb9600846a700faef5e60 + * 验证目的:值为数字 0 的透视树父节点仍能展开子维度。 + * 改写:将来源远程数据替换为固定公开记录,保留零值、双层行维度及录制展开动作。 + */ +export default { + mount(container) { + // 零值类别和普通类别并存,用于识别把 0 错当空值的层级处理。 + container.style.width = '800px'; + container.style.height = '400px'; + return new window.VTable.PivotTable(container, { + records: [ + { category: 0, item: 'Zero A', region: 'East', quantity: 2 }, + { category: 0, item: 'Zero B', region: 'West', quantity: 3 }, + { category: 'Other', item: 'Other A', region: 'East', quantity: 4 }, + { category: 'Other', item: 'Other B', region: 'West', quantity: 5 } + ], + rows: [{ dimensionKey: 'category', title: 'Category', width: 'auto' }, + { dimensionKey: 'item', title: 'Item', width: 'auto' }], + columns: [{ dimensionKey: 'region', title: 'Region', width: 'auto' }], + indicators: [{ indicatorKey: 'quantity', title: 'Quantity', width: 'auto' }], + rowHierarchyType: 'tree', rowExpandLevel: 1, widthMode: 'standard' + }); + }, + async exercise(page) { + // 在表头以下定位数字 0 所在行,再点击该行左侧层级图标。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const row = Array.from({ length: table.rowCount }, (_, index) => index) + .find(index => table.getCellValue(0, index) === 0); + if (row === undefined || table.getHierarchyState(0, row) !== 'collapse') + throw new Error('未找到可展开的零值父节点'); + const b = table.getCellRect(0, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 23, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 数字 0 父节点必须转为展开并显示两个子项。 + await page.waitForFunction(() => { + const table = window.__visualTable; + const row = Array.from({ length: table.rowCount }, (_, index) => index) + .find(index => table.getCellValue(0, index) === 0); + return row !== undefined && table.getHierarchyState(0, row) === 'expand'; + }); + await page.evaluate(() => { + if (window.__visualTable.rowCount < 5) throw new Error('零值类别的子项未进入可见行'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/update-filter.mjs b/packages/vtable/__tests__/visual/cases/pivot/update-filter.mjs new file mode 100644 index 0000000000..cbe330b010 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/update-filter.mjs @@ -0,0 +1,32 @@ +/** + * BugServer case IDs: 66da9cdd0846a700faef5def + * 验证目的:透视表初始化过滤规则后由 updateFilterRules 替换条件并重新聚合。 + * 改写:记录换成固定交叉分组,保留先过滤一组再改为另一组的顺序。 + */ +export default { + mount(container) { + // 最终规则剔除 R1/A,允许 R2/A 重新进入汇总。 + const table = new window.VTable.PivotTable(container, { + rows: ['region', 'item'], columns: ['kind', 'variant'], indicators: ['amount', 'count'], + enableDataAnalysis: true, indicatorsAsCol: true, + dataConfig: { filterRules: [{ filterFunc: record => !(record.region === 'R2' && record.kind === 'A') }], + totals: { row: { subTotalsDimensions: ['region'] } } }, + records: [{ region: 'R1', item: 'I1', kind: 'A', variant: 'A1', amount: 10, count: 1 }, + { region: 'R1', item: 'I2', kind: 'B', variant: 'B1', amount: 20, count: 2 }, + { region: 'R2', item: 'I1', kind: 'A', variant: 'A1', amount: 30, count: 3 }, + { region: 'R2', item: 'I2', kind: 'B', variant: 'B1', amount: 40, count: 4 }] + }); + table.updateFilterRules([{ filterFunc: record => !(record.region === 'R1' && record.kind === 'A') }]); + return table; + }, + async verify(page) { + // 更新后的透视值应包含 R2/A 的 30,且排除 R1/A 的 10。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (!values.includes(30) || values.includes(10)) throw new Error('透视过滤规则未替换'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/update-option-row-header-width.mjs b/packages/vtable/__tests__/visual/cases/pivot/update-option-row-header-width.mjs new file mode 100644 index 0000000000..92a4cf2fe6 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/update-option-row-header-width.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 6a95269bcf3b32005d0b9b74 + * 验证目的:grid-tree 透视表 updateOption 后,四级行表头列宽不回退到默认值。 + * 改写:压缩重复记录和状态标签,保留相同配置更新及列宽前后比较。 + */ +export default { + mount(container) { + // 四级行维度和行列合计共同触发行头宽度重算路径。 + container.style.height = '500px'; + const option = { + records: [{ year: '2022', region: 'East', segment: 'Consumer', mode: 'First', category: 'A', item: 'A1', sales: 891, profit: 112 }, + { year: '2022', region: 'East', segment: 'Corporate', mode: 'Second', category: 'A', item: 'A2', sales: 496, profit: 48 }, + { year: '2023', region: 'West', segment: 'Consumer', mode: 'Standard', category: 'B', item: 'B1', sales: 895, profit: 152 }], + rows: ['year', 'region', 'segment', 'mode'], columns: ['category', 'item'], + indicators: ['sales', 'profit'], enableDataAnalysis: true, indicatorTitle: 'Indicators', + rowExpandLevel: Infinity, defaultColWidth: 120, defaultRowHeight: 32, + widthMode: 'standard', heightMode: 'standard', + rowHierarchyType: 'grid-tree', columnHierarchyType: 'grid-tree', + corner: { titleOnDimension: 'column' }, + dataConfig: { totals: { row: { showGrandTotals: true, showSubTotals: true, + subTotalsDimensions: ['year', 'region', 'segment'], grandTotalLabel: 'Total', subTotalLabel: 'Subtotal' }, + column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['category'], + grandTotalLabel: 'Total', subTotalLabel: 'Subtotal' } } } + }; + const table = new window.VTable.PivotTable(container, option); + window.__beforeWidths = [0, 1, 2, 3].map(col => table.getColWidth(col)); + table.updateOption(option, { clearColWidthCache: false }); + return table; + }, + async verify(page) { + // 更新后的行头宽度应与更新前一致且不会全回退到 80。 + await page.evaluate(() => { + const table = window.__visualTable; + const after = [0, 1, 2, 3].map(col => table.getColWidth(col)); + if (after.some((width, i) => Math.abs(width - window.__beforeWidths[i]) > 1) || + after.every(width => Math.round(width) === 80)) + throw new Error(`行头宽度更新异常: ${window.__beforeWidths} => ${after}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/update-pivot-sort-state-click.mjs b/packages/vtable/__tests__/visual/cases/pivot/update-pivot-sort-state-click.mjs new file mode 100644 index 0000000000..34ed9d2299 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/update-pivot-sort-state-click.mjs @@ -0,0 +1,73 @@ +/** + * BugServer case IDs: 6708f3b739265200a62f816c + * 验证目的:点击透视表排序图标后,通过 pivot_sort_click 更新 pivotSortState。 + * 改写:日期与指标名称换成固定通用字段,保留虚拟列树与事件回写路径。 + */ +export default { + mount(container) { + // 排序图标出现在两个行维度及部分指标中,事件回调统一写入降序状态。 + const table = new window.VTable.PivotTable(container, { + records: [ + { day: '2024-08-01', week: 'Thu', quantityA: 1, amountA: 4, quantityB: 2, amountB: 2 }, + { day: '2024-08-03', week: 'Sat', quantityA: 2, amountA: 3, quantityB: 2, amountB: 2 }, + { day: '2024-08-07', week: 'Wed', quantityA: 3, amountA: 2, quantityB: 2, amountB: 2 }, + { day: '2024-08-09', week: 'Fri', quantityA: 4, amountA: 1, quantityB: 2, amountB: 2 } + ], + rows: [{ dimensionKey: 'day', title: 'Day', showSort: true, width: 120 }, + { dimensionKey: 'week', title: 'Week', showSort: true, width: 90 }], + columns: [{ dimensionKey: 'group', title: 'Group' }], + columnTree: [ + { dimensionKey: 'group', value: 'A', virtual: true, + children: [{ indicatorKey: 'quantityA' }, { indicatorKey: 'amountA' }] }, + { dimensionKey: 'group', value: 'B', virtual: true, + children: [{ indicatorKey: 'quantityB' }, { indicatorKey: 'amountB' }] } + ], + indicators: [{ indicatorKey: 'quantityA', title: 'Quantity A', showSort: true }, + { indicatorKey: 'amountA', title: 'Amount A', showSort: true }, + { indicatorKey: 'quantityB', title: 'Quantity B' }, + { indicatorKey: 'amountB', title: 'Amount B' }], + corner: { titleOnDimension: 'all' }, widthMode: 'standard' + }); + window.__pivotSortClicks = 0; + table.on('pivot_sort_click', event => { + // 与来源相同,外部业务处理后把点击维度写回专用排序状态接口。 + window.__pivotSortClicks++; + table.updatePivotSortState([{ dimensions: event.dimensionInfo, order: 'desc' }]); + table.renderWithRecreateCells(); + }); + return table; + }, + async exercise(page) { + // 查找首个透视排序图标并真正点击,避免直接设置状态绕过事件。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + for (let row = 0; row < table.rowCount; row++) { + for (let col = 0; col < table.colCount; col++) { + const stack = [table.scenegraph.getCell(col, row)]; + while (stack.length) { + const mark = stack.pop(); + if (mark?.attribute?.funcType === 'sort') { + const bounds = mark.globalAABBBounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, + y: host.y + (bounds.y1 + bounds.y2) / 2 }; + } + stack.push(...(mark?.children ?? [])); + } + } + } + throw new Error('透视排序图标缺失'); + }); + await page.mouse.click(point.x, point.y); + await page.waitForFunction(() => window.__pivotSortClicks > 0); + }, + async verify(page) { + // 事件发生后专用 pivotSortState 必须保存一条降序维度路径。 + await page.evaluate(() => { + const table = window.__visualTable; + if (window.__pivotSortClicks < 1 || table.pivotSortState?.[0]?.order !== 'desc' || + !table.pivotSortState[0].dimensions?.length) + throw new Error(`透视排序状态未回写:${JSON.stringify(table.pivotSortState)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/virtual-column-total.mjs b/packages/vtable/__tests__/visual/cases/pivot/virtual-column-total.mjs new file mode 100644 index 0000000000..c2e3628c21 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/virtual-column-total.mjs @@ -0,0 +1,48 @@ +/** + * BugServer case IDs: 66418ee40b3b8900c63a7808 + * 验证目的:虚拟列节点与行列小计、总计共同布局。 + * 改写:保留两层虚拟节点及合计规则,明细改为通用分组数据。 + */ +export default { + mount(container) { + // 虚拟节点自身不对应数据维度,子节点仍需参与聚合。 + return new window.VTable.PivotTable(container, { + rows: ['region', 'item'], columns: ['kind', 'variant'], indicators: ['amount', 'count'], + columnTree: [ + { dimensionKey: 'kind', value: 'Column Total', children: [] }, + { dimensionKey: 'virtualGroup', value: 'Virtual', virtual: true, children: [ + { dimensionKey: 'kind', value: 'A', children: [ + { dimensionKey: 'variant', value: 'A1', children: [] }, + { dimensionKey: 'variant', value: 'Subtotal', children: [] }, + { dimensionKey: 'variant', value: 'A2', children: [] } + ] }, + { dimensionKey: 'kind', value: 'B', children: [ + { dimensionKey: 'virtualNested', value: 'Nested virtual', virtual: true, children: [ + { dimensionKey: 'variant', value: 'Subtotal', children: [] }, + { dimensionKey: 'variant', value: 'B1', children: [] } + ] } + ] } + ] } + ], + dataConfig: { totals: { + row: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['region'], + grandTotalLabel: 'Row total', subTotalLabel: 'Subtotal', showSubTotalsOnTop: true, showGrandTotalsOnTop: true }, + column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['kind'], + grandTotalLabel: 'Column Total', subTotalLabel: 'Subtotal', showSubTotalsOnLeft: true, showGrandTotalsOnLeft: true } + } }, + records: [ + { region: 'R1', item: 'I1', kind: 'A', variant: 'A1', amount: 10, count: 1 }, + { region: 'R1', item: 'I2', kind: 'A', variant: 'A2', amount: 20, count: 2 }, + { region: 'R2', item: 'I1', kind: 'B', variant: 'B1', amount: 30, count: 3 } + ], + enableDataAnalysis: true, indicatorsAsCol: false, corner: { titleOnDimension: 'row' }, widthMode: 'autoWidth' + }); + }, + async verify(page) { + // 虚拟表头展开后应有足够的行列,且原始数值仍可检索。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount < 5 || table.rowCount < 5) throw new Error('虚拟节点未展开'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/context-menu-click.mjs b/packages/vtable/__tests__/visual/cases/plugins/context-menu-click.mjs new file mode 100644 index 0000000000..eb0c888202 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/context-menu-click.mjs @@ -0,0 +1,37 @@ +/** + * BugServer case IDs: 6a82b5b68e0a21005e44edc9 + * 验证目的:ContextMenuPlugin 的冻结菜单回调发出 context_menu_click 事件。 + * 改写:去掉状态文本面板,保留插件回调的 menuKey、行列坐标和事件。 + */ +export default { + mount(container) { + // 监听事件在执行菜单回调前安装,防止同步触发被漏掉。 + const plugin = new window.VTable.plugins.ContextMenuPlugin(); + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 80 }, { field: 'name', title: 'Name', width: 160 }, + { field: 'city', title: 'City', width: 160 }, { field: 'value', title: 'Value', width: 120 }], + records: Array.from({ length: 8 }, (_, i) => ({ id: i + 1, name: `Name ${i + 1}`, + city: ['North', 'South', 'East'][i % 3], value: Math.round((i + 1) * 12.6) })), + defaultRowHeight: 40, defaultHeaderRowHeight: 40, widthMode: 'standard', + heightMode: 'standard', plugins: [plugin] + }); + window.__contextPlugin = plugin; + window.__contextEvents = []; + table.on('context_menu_click', args => window.__contextEvents.push(args)); + return table; + }, + async exercise(page) { + // 调用来源相同的冻结菜单回调,验证插件而非手工伪造事件。 + await page.evaluate(() => { + const plugin = window.__contextPlugin; + if (typeof plugin.handleMenuClickCallback !== 'function') throw new Error('菜单插件回调缺失'); + plugin.handleMenuClickCallback({ menuKey: 'freeze_to_this_row_and_column', + menuText: 'Freeze to cell', rowIndex: 1, colIndex: 1 }, window.__visualTable); + }); + }, + async verify(page) { + // 必须收到插件真实发出的目标菜单事件。 + await page.waitForFunction(() => window.__contextEvents.some(event => + event.contextMenu?.menuKey === 'freeze_to_this_row_and_column')); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/fill-handle-hit-area.mjs b/packages/vtable/__tests__/visual/cases/plugins/fill-handle-hit-area.mjs new file mode 100644 index 0000000000..a189ffa806 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/fill-handle-hit-area.mjs @@ -0,0 +1,31 @@ +/** + * BugServer case IDs: 6aaf3468168db9005cc382c1 + * 验证目的:填充柄显示尺寸为 6×6,命中区域覆盖 11 像素且不覆盖 13 像素。 + * 改写:移除宿主状态标签,保留选中、两个偏移命中检查与尺寸断言。 + */ +export default { + mount(container) { + // 开启 fillHandle 并选中第一个数据格,命中检查在渲染后运行。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 180 }, { field: 'value', title: 'Value', width: 180 }], + records: [{ name: 'Alpha', value: 1 }, { name: 'Beta', value: 2 }, { name: 'Gamma', value: 3 }], + excelOptions: { fillHandle: true } + }); + table.selectCell(0, 1); + return table; + }, + async verify(page) { + // 同时检查真实命中函数与显示大小,避免只有配置存在的假通过。 + await page.evaluate(() => { + const table = window.__visualTable; + const bounds = table.scenegraph.highPerformanceGetCell(0, 1).globalAABBBounds; + const hit = offset => table.eventManager.checkCellFillhandle({ + abstractPos: { x: bounds.x2 + offset, y: bounds.y2 + offset }, eventArgs: {} + }); + const component = [...table.scenegraph.selectedRangeComponents.values()][0]; + if (!component?.fillhandle || !hit(11) || hit(13) || + component.fillhandle.attribute.width !== 6 || component.fillhandle.attribute.height !== 6) + throw new Error('填充柄命中区域或视觉尺寸错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/filter-hide-reorder.mjs b/packages/vtable/__tests__/visual/cases/plugins/filter-hide-reorder.mjs new file mode 100644 index 0000000000..bacbf57573 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/filter-hide-reorder.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6a0c22678e0a21005e44ed8a + * 验证目的:FilterPlugin 与隐藏列、移动表头连续执行后筛选结果仍正确。 + * 改写:来源的人事字段及示例姓名改为通用项,保留三步调用顺序。 + */ +export default { + mount(container) { + // 记录包含两种保留状态与一种剔除状态,验证插件筛选生效。 + const filter = new window.VTable.plugins.FilterPlugin({}); + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'id', title: 'ID', width: 80, sort: true }, + { field: 'name', title: 'Name', width: 120, sort: true }, + { field: 'group', title: 'Group', width: 100 }, + { field: 'city', title: 'City', width: 120 }, + { field: 'status', title: 'Status', width: 120 } + ], + records: [ + { id: 1, name: 'A', group: 'G1', city: 'North', status: 'Active' }, + { id: 2, name: 'B', group: 'G2', city: 'South', status: 'Leave' }, + { id: 3, name: 'C', group: 'G1', city: 'East', status: 'Active' }, + { id: 4, name: 'D', group: 'G2', city: 'West', status: 'Inactive' } + ], + padding: 10, dragHeaderMode: 'all', plugins: [filter] + }); + const nextColumns = table.columns.map(column => ({ ...column, ...(column.field === 'group' ? { hide: true } : {}) })); + table.updateColumns(nextColumns, { clearRowHeightCache: false }); + const city = table.columns.findIndex(column => column.field === 'city'); + const name = table.columns.findIndex(column => column.field === 'name'); + table.changeHeaderPosition({ source: { col: city, row: 0 }, target: { col: name + 1, row: 0 }, movingColumnOrRow: 'column' }); + filter.applyFilterSnapshot({ filters: [{ field: 'status', type: 'byValue', values: ['Active', 'Leave'], enable: true }] }); + return table; + }, + async verify(page) { + // 验证筛选剔除了目标记录,且隐藏列及表头移动调用未丢失。 + await page.evaluate(() => { + const table = window.__visualTable; + const records = table.getFilteredRecords(); + if (records.length !== 3 || records.some(record => record.status === 'Inactive')) + throw new Error('插件筛选结果错误'); + if (!table.columns.some(column => column.field === 'group' && column.hide)) + throw new Error('隐藏列未保留'); + if (table.columns.findIndex(column => column.field === 'city') <= table.columns.findIndex(column => column.field === 'name')) + throw new Error('表头移动未保留'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/highlight-header.mjs b/packages/vtable/__tests__/visual/cases/plugins/highlight-header.mjs new file mode 100644 index 0000000000..5be74880a3 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/highlight-header.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 68ef4fe025696c00b26a774c + * 验证目的:选中透视表体后插件高亮对应的行列标题。 + * 改写:多地区商品明细换成固定通用分组,保留插件双向高亮与点击。 + */ +export default { + mount(container) { + // 插件实例留作状态断言,表格数据构成可见的行列交叉。 + const plugin = new window.VTable.plugins.HighlightHeaderWhenSelectCellPlugin({ rowHighlight: true, colHighlight: true }); + window.__highlightPlugin = plugin; + return new window.VTable.PivotTable(container, { + plugins: [plugin], rows: ['group', 'item'], columns: ['kind', 'variant'], + indicators: ['amount', 'count'], indicatorsAsCol: false, enableDataAnalysis: true, + records: [{ group: 'A', item: 'A1', kind: 'X', variant: 'X1', amount: 10, count: 1 }, + { group: 'A', item: 'A2', kind: 'Y', variant: 'Y1', amount: 20, count: 2 }, + { group: 'B', item: 'B1', kind: 'X', variant: 'X1', amount: 30, count: 3 }] + }); + }, + async exercise(page) { + // 点击首个表体数值,对应来源的 click-cell 录制动作。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const b = table.getCellRect(table.rowHeaderLevelCount, table.columnHeaderLevelCount).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 插件应产生行列标题高亮范围。 + await page.waitForFunction(() => window.__highlightPlugin.rowHeaderRanges.length && window.__highlightPlugin.colHeaderRanges.length); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/master-detail-auto-height.mjs b/packages/vtable/__tests__/visual/cases/plugins/master-detail-auto-height.mjs new file mode 100644 index 0000000000..b06a947663 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/master-detail-auto-height.mjs @@ -0,0 +1,53 @@ +/** + * BugServer case IDs: 68ff3ba0e9f70b00b11e9403 + * 验证目的:MasterDetailPlugin 自动高度子表在主表滚动后仍正确布局。 + * 改写:来源的人员、部门与薪资示例替换为固定任务数据,保留展开子表、自动高度及滚动条件。 + */ +export default { + mount(container) { + // 每四条记录带一张子表,保证容器高度不足时仍有已展开的明细。 + container.style.width = '800px'; + container.style.height = '400px'; + const plugin = new window.VTable.plugins.MasterDetailPlugin({ + id: 'visual-master-detail', + detailTableOptions: { + columns: [{ field: 'step', title: 'Step', width: 180 }, + { field: 'state', title: 'State', width: 140 }], + defaultRowHeight: 35, defaultHeaderRowHeight: 35, + style: { margin: 15, height: 'auto' }, theme: window.VTable.themes.ARCO + } + }); + const records = Array.from({ length: 12 }, (_, index) => ({ + id: index + 1, item: `Task ${index + 1}`, stage: index % 2 ? 'Pending' : 'Ready', + hierarchyState: 'expand', + children: index % 4 === 0 ? [ + { step: 'Prepare', state: 'Done' }, { step: 'Review', state: 'Open' } + ] : undefined + })); + return new window.VTable.ListTable(container, { + records, + columns: [{ field: 'id', title: 'ID', width: 80 }, + { field: 'item', title: 'Task', width: 180 }, + { field: 'stage', title: 'Stage', width: 130 }], + rowSeriesNumber: { title: '#', dragOrder: true, width: 'auto' }, + widthMode: 'standard', heightMode: 'standard', defaultRowHeight: 40, + defaultHeaderRowHeight: 45, plugins: [plugin] + }); + }, + async exercise(page) { + // 将来源滚动条到底动作转换为定位最后一行,避免固定像素坐标。 + await page.evaluate(() => { + const table = window.__visualTable; + table.scrollToCell({ row: table.rowCount - 1 }); + }); + }, + async verify(page) { + // 滚动后主从展开行仍要保持自动高度和有效布局。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getHierarchyState(1, 1) !== 'expand' || table.getRowHeight(1) <= 40 || + table.scrollTop <= 0 || !Number.isFinite(table.getCellRect(1, table.rowCount - 1)?.bounds?.y1)) + throw new Error(`MasterDetail 明细或滚动未生效:height=${table.getRowHeight(1)}, top=${table.scrollTop}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/add-merged.mjs b/packages/vtable/__tests__/visual/cases/records/add-merged.mjs new file mode 100644 index 0000000000..b02143f3a1 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/add-merged.mjs @@ -0,0 +1,29 @@ +/** + * BugServer case IDs: 6614e7b82acd9c00d1c98a62 + * 验证目的:合并单元格分组中插入记录后合并区域正常重算。 + * 改写:分组和编号改成通用值,保留中间位置插入。 + */ +export default { + mount(container) { + // 在第二组已有记录前插入同组项目。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'select', title: '', cellType: 'checkbox', headerType: 'checkbox', width: 60 }, + { field: 'group', title: 'Group', width: 120 }, + { field: 'label', title: 'Label', width: 150, mergeCell: true }, + { field: 'id', title: 'ID', width: 100 }], + records: [{ group: 'A', label: 'Group A', id: 1 }, { group: 'A', label: 'Group A', id: 2 }, + { group: 'B', label: 'Group B', id: 3 }, { group: 'B', label: 'Group B', id: 4 }], + autoWrapText: true, heightMode: 'autoHeight' + }); + table.addRecord({ group: 'B', label: 'Group B', id: 5 }, 3); + return table; + }, + async verify(page) { + // 插入记录可见,且合并列仍返回组名。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount !== 6 || table.getCellOriginValue(3, 4) !== 5 || table.getCellValue(2, 4) !== 'Group B') + throw new Error('合并分组插入失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/add-pagination.mjs b/packages/vtable/__tests__/visual/cases/records/add-pagination.mjs new file mode 100644 index 0000000000..4b6be97fd6 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/add-pagination.mjs @@ -0,0 +1,31 @@ +/** + * BugServer case IDs: 656d91b34c3611faee9b1b2e + * 验证目的:第一页开启分页时,在记录索引 2 批量插入后可见顺序正确。 + * 改写:人员资料与联系方式替换为固定编号,保留 50 条数据和每页 7 条配置。 + */ +export default { + mount(container) { + // 两条新记录应出现在第一页第 3-4 条,后续旧记录顺延。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'label', title: 'Label', width: 180 }, + { field: 'progress', title: 'Progress', width: 130 }], + records: Array.from({ length: 50 }, (_, index) => ({ id: index + 1, + label: `Item ${index + 1}`, progress: index })), + pagination: { perPageCount: 7, currentPage: 0 }, + widthMode: 'standard', allowFrozenColCount: 2 + }); + table.addRecords([{ id: 201, label: 'Inserted A' }, + { id: 202, label: 'Inserted B' }], 2); + return table; + }, + async verify(page) { + // 插入必须影响分页当前页而非仅修改原始 records 数组。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.records.length !== 52 || table.getCellValue(0, 3) !== 201 || + table.getCellValue(0, 4) !== 202 || table.getCellValue(0, 5) !== 3) + throw new Error('分页插入顺序错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/add-sorted.mjs b/packages/vtable/__tests__/visual/cases/records/add-sorted.mjs new file mode 100644 index 0000000000..15fd41a963 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/add-sorted.mjs @@ -0,0 +1,30 @@ +/** + * BugServer case IDs: 656d93014c3611faee9b1b30 + * 验证目的:按名字排序后,在索引 2 插入缺名字和有名字的两条记录。 + * 改写:保留 50 条初始记录、排序状态和两种插入边界,去掉展示型 SVG。 + */ +export default { + mount(container) { + // 在已有排序状态下批量插入,其中第一条缺失排序字段。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'fname', title: 'First Name', width: 150, sort: true }, + { field: 'progress', title: 'Progress', width: 120 }], + widthMode: 'standard' + }); + const names = ['Sophia', 'Emma', 'Olivia', 'Isabella', 'Ava', 'Mia', 'Emily', 'Abigail', 'Madison', 'Elizabeth']; + table.setRecords(Array.from({ length: 50 }, (_, i) => + ({ id: i + 1, fname: names[i % names.length], progress: i })), { field: 'fname', order: 'asc' }); + table.addRecords([{ id: 201 }, { id: 202, fname: 'Zsagjkf' }], 2); + return table; + }, + async verify(page) { + // 两条不同形态的新记录都应保留,且排序状态没有丢失。 + await page.evaluate(() => { + const table = window.__visualTable; + const ids = Array.from({ length: table.rowCount - 1 }, (_, i) => table.getCellOriginValue(0, i + 1)); + if (table.rowCount !== 53 || !ids.includes(201) || !ids.includes(202) || table.sortState?.field !== 'fname') + throw new Error('排序后插入记录失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/array-path-add.mjs b/packages/vtable/__tests__/visual/cases/records/array-path-add.mjs new file mode 100644 index 0000000000..26501c4451 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/array-path-add.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 676e651d8e768100b114c2ef + * 验证目的:点号路径读取数组元素字段后,在中间插入一条数组记录。 + * 改写:将姓名改为通用标识,保留 0.name/1.age/2.sex 路径和插入位置。 + */ +export default { + mount(container) { + // 数组记录的路径与普通对象路径不同,插入后还须能解析。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: '0.name', title: 'Name', width: 130, sort: true }, + { field: '1.age', title: 'Age', width: 100 }, { field: '2.sex', title: 'Sex', width: 100 }], + records: [[{ name: 'A' }, { age: 20 }, { sex: 'male' }], + [{ name: 'B' }, { age: 21 }, { sex: 'female' }], [{ name: 'C' }, { age: 22 }, { sex: 'male' }]] + }); + table.addRecord([{ name: 'Inserted' }, { age: 23 }, { sex: 'female' }], 2); + return table; + }, + async verify(page) { + // 插入后的三个字段必须落在同一行。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 3) !== 'Inserted' || table.getCellValue(1, 3) !== 23 || + table.getCellValue(2, 3) !== 'female') throw new Error('数组字段路径或插入位置错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/delete-all-bottom-frozen.mjs b/packages/vtable/__tests__/visual/cases/records/delete-all-bottom-frozen.mjs new file mode 100644 index 0000000000..c391eaa2de --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/delete-all-bottom-frozen.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 6aacad9f168db9005cc382be + * 验证目的:删除全部记录后,底部冻结行数量重置为零。 + * 改写:保留左右冻结列、底部冻结行和删除两条记录的顺序。 + */ +export default { + mount(container) { + // 先创建冻结区,再删除所有数据,防止仅测试空表初始化。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 120 }, { field: 'name', title: 'Name', width: 300 }, + { field: 'total', title: 'Total', width: 180 }], + records: [{ id: 1, name: 'A', total: 120 }, { id: 2, name: 'B', total: 180 }], + frozenColCount: 1, rightFrozenColCount: 1, bottomFrozenRowCount: 1, widthMode: 'standard' + }); + table.deleteRecords([0, 1]); + return table; + }, + async verify(page) { + // 删除必须同时清空数据和底部冻结计数。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.records.length !== 0 || table.bottomFrozenRowCount !== 0) + throw new Error('删除全部记录后仍保留底部冻结行'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/delete-merged.mjs b/packages/vtable/__tests__/visual/cases/records/delete-merged.mjs new file mode 100644 index 0000000000..f41f5f5045 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/delete-merged.mjs @@ -0,0 +1,29 @@ +/** + * BugServer case IDs: 6614e84b2acd9c00d1c98a63 + * 验证目的:删除合并单元格分组中的记录后合并区域正常重算。 + * 改写:使用通用编号,保留末行删除。 + */ +export default { + mount(container) { + // 删除第二组末行,防止合并边界残留。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'select', title: '', cellType: 'checkbox', headerType: 'checkbox', width: 60 }, + { field: 'group', title: 'Group', width: 120 }, + { field: 'label', title: 'Label', width: 150, mergeCell: true }, + { field: 'id', title: 'ID', width: 100 }], + records: [{ group: 'A', label: 'Group A', id: 1 }, { group: 'A', label: 'Group A', id: 2 }, + { group: 'B', label: 'Group B', id: 3 }, { group: 'B', label: 'Group B', id: 4 }], + autoWrapText: true, heightMode: 'autoHeight' + }); + table.deleteRecords([3]); + return table; + }, + async verify(page) { + // 最后一行变为 ID 3,合并组名仍可见。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount !== 4 || table.getCellOriginValue(3, 3) !== 3 || table.getCellValue(2, 3) !== 'Group B') + throw new Error('合并分组删除失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/delete-sorted.mjs b/packages/vtable/__tests__/visual/cases/records/delete-sorted.mjs new file mode 100644 index 0000000000..6bc1ac85a9 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/delete-sorted.mjs @@ -0,0 +1,30 @@ +/** + * BugServer case IDs: 656d995d4c3611faee9b1b33 + * 验证目的:按名字排序的 50 条记录删除索引 0 和 8 后重算表体。 + * 改写:保留排序与双索引删除,去掉展示型 SVG 和无关字段。 + */ +export default { + mount(container) { + // 排序完成后删除两个非连续索引,检查记录数和排序状态。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { field: 'fname', title: 'First Name', width: 150, sort: true }, + { field: 'progress', title: 'Progress', width: 120 }], + widthMode: 'standard' + }); + const names = ['Sophia', 'Emma', 'Olivia', 'Isabella', 'Ava', 'Mia', 'Emily', 'Abigail', 'Madison', 'Elizabeth']; + table.setRecords(Array.from({ length: 50 }, (_, i) => + ({ id: i + 1, fname: names[i % names.length], progress: i })), { field: 'fname', order: 'asc' }); + table.deleteRecords([0, 8]); + return table; + }, + async verify(page) { + // 删除后只余 48 条记录,排序状态仍指向 fname。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount !== 49 || table.sortState?.field !== 'fname' || + !Number.isFinite(table.getCellRect(1, 48)?.bounds?.y1)) + throw new Error('排序后删除记录失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/records/update-merged.mjs b/packages/vtable/__tests__/visual/cases/records/update-merged.mjs new file mode 100644 index 0000000000..d596709e22 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/records/update-merged.mjs @@ -0,0 +1,37 @@ +/** + * BugServer case IDs: 6614e8b42acd9c00d1c98a64 + * 验证目的:分组合并单元格存在时,updateRecords 更新目标记录且合并范围保持正确。 + * 改写:用通用组编号与短文本替换原示例,保留五行分组和索引 1 的更新路径。 + */ +export default { + mount(container) { + // 前三行同组、后两行同组,用于检查更新后的跨行合并。 + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'select', title: '', width: 60, cellType: 'checkbox', headerType: 'checkbox' }, + { field: 'groupNo', title: 'Group No.', width: 120 }, + { field: 'groupName', title: 'Group', width: 150, mergeCell: true }, + { field: 'item', title: 'Item', width: 120 } + ], + records: [ + { groupNo: '0001', groupName: 'Group 1', item: 'A' }, + { groupNo: '0001', groupName: 'Group 1', item: 'B' }, + { groupNo: '0001', groupName: 'Group 1', item: 'C' }, + { groupNo: '0002', groupName: 'Group 2', item: 'D' }, + { groupNo: '0002', groupName: 'Group 2', item: 'E' } + ], + autoWrapText: true, heightMode: 'autoHeight' + }); + table.updateRecords([{ groupNo: '0001', groupName: 'Group 1', item: 'Updated' }], [1]); + return table; + }, + async verify(page) { + // 更新值与第一组合并区间都应真实可读。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(3, 2) !== 'Updated') throw new Error('记录更新未生效'); + const range = table.getCellRange(2, 1); + if (range.start.row !== 1 || range.end.row !== 3) throw new Error('分组合并范围错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/scroll/bar-to-side.mjs b/packages/vtable/__tests__/visual/cases/scroll/bar-to-side.mjs new file mode 100644 index 0000000000..9ca8d009a5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/scroll/bar-to-side.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 66055f07a8fccc00acd3703a + * 验证目的:列溢出时滚动条贴边且始终可见,多层表头保持布局。 + * 改写:原例人物资料改为固定通用记录,保留列宽和 scrollStyle 关键设置。 + */ +export default { + mount(container) { + // 宽度总和超过 800px,确保可见滚动条不是无溢出的空配置。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 'calc(20% - 20px)', + fieldFormat: record => `Completed ${record.progress}%` }, + { title: 'Name', columns: [ + { field: 'first', title: 'First name', width: 180, minWidth: 150 }, + { field: 'last', title: 'Last name', width: '20%', minWidth: 150 } + ] }, + { field: 'note', title: 'Note', width: 650 } + ], + records: [{ progress: 20, first: 'A', last: 'One', note: 'first' }, + { progress: 50, first: 'B', last: 'Two', note: 'second' }], + dragHeaderMode: 'column', defaultHeaderColWidth: [80, 150], + theme: { scrollStyle: { barToSide: true, visible: 'always' } } + }); + }, + async verify(page) { + // 验证水平内容确实溢出,否则滚动条样式无法得到有效测试。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getAllColsWidth() <= 800 || table.getCellValue(1, 3) !== 'B') + throw new Error('滚动表格未形成预期溢出'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/scroll/pivot-wide-rail.mjs b/packages/vtable/__tests__/visual/cases/scroll/pivot-wide-rail.mjs new file mode 100644 index 0000000000..8abdc24c87 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/scroll/pivot-wide-rail.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 689af66784406200a7ab3d6c + * 验证目的:透视表宽滚动条、贴边轨道、主题条纹和可调整行高共同布局。 + * 改写:用固定组合生成多行多列,保留 30 像素轨道及 always 配置。 + */ +export default { + mount(container) { + // 足够的维度组合同时触发水平和垂直滚动条。 + const records = []; + for (let group = 0; group < 8; group++) + for (let item = 0; item < 3; item++) + for (let kind = 0; kind < 8; kind++) + records.push({ group: `G${group}`, item: `I${item}`, kind: `K${kind}`, variant: `V${kind}`, + amount: group * 100 + item * 10 + kind, count: 1 }); + return new window.VTable.PivotTable(container, { + rows: ['group', 'item'], columns: ['kind', 'variant'], indicators: ['amount', 'count'], + records, enableDataAnalysis: true, indicatorsAsCol: false, + rowResizeType: 'indicator', rowResizeMode: 'all', widthMode: 'autoWidth', + theme: window.VTable.themes.ARCO.extends({ + scrollStyle: { width: 30, visible: 'always', hoverOn: false, barToSide: true, + scrollSliderCornerRadius: 0, scrollRailColor: 'rgba(216,216,216,.5)', scrollSliderColor: 'rgba(170,170,170,1)' }, + bodyStyle: { bgColor: args => (args.row - args.table.frozenRowCount) % 2 ? '#f8f8f8' : '#ffffff' } + }) + }); + }, + async verify(page) { + // 透视尺寸应超过视口,确保滚动条确实有内容可滚动。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount < 8 || table.rowCount < 20) throw new Error('透视滚动范围不足'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/add-columns.mjs b/packages/vtable/__tests__/visual/cases/sheet/add-columns.mjs new file mode 100644 index 0000000000..18f60a0828 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/add-columns.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 68ff1c25f11ddd816792f91a + * 验证目的:Sheet 中公式和表格列插入后仍能渲染。 + * 改写:移除与列插入无关的菜单、主题和实验性插件配置,保留公式与 addColumns 调用。 + */ +export default { + mount(container) { + // 使用固定矩阵避免异步数据源影响列插入的可重复性。 + container.style.height = '400px'; + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ + rowCount: 20, columnCount: 10, sheetKey: 'sheet1', sheetTitle: 'Sheet 1', + filter: true, columns: [{ title: 'Name', sort: true, width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['A', 'B', 'C']], active: true + }] + }); + sheet.formulaManager.setCellContent({ sheet: 'sheet1', row: 4, col: 3 }, '=SUM(A2:C2)'); + const table = sheet.getActiveSheet().tableInstance; + window.__sheetColsBefore = table.colCount; + table.addColumns([{ field: 3 }, { field: 4 }], 3, true); + return sheet; + }, + async verify(page) { + // 断言活动 Sheet 存在且插入操作改变列结构。 + await page.evaluate(() => { + const sheet = window.__visualTable; + const table = sheet.getActiveSheet()?.tableInstance; + if (!table || table.colCount <= window.__sheetColsBefore) throw new Error('Sheet 列插入未生效'); + if (!Number.isFinite(table.getCellRect(1, 1)?.bounds?.x1)) throw new Error('Sheet 单元格未布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/add-rows.mjs b/packages/vtable/__tests__/visual/cases/sheet/add-rows.mjs new file mode 100644 index 0000000000..1af92ca9b6 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/add-rows.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 68ff1f7b25696c00b26a7761 + * 验证目的:Sheet 调整行高并插入两行后,原有数据仍位于正确位置。 + * 改写:保留行高调整、addRecords 与编辑动作,移除无关菜单和插件。 + */ +export default { + mount(container) { + // 固定矩阵及公式,使插入前后的单元格位置可验证。 + container.style.height = '400px'; + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 20, columnCount: 10, + columns: [{ title: 'Name', sort: true, width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['A', 'B', 'C']], active: true }] + }); + const table = sheet.getActiveSheet().tableInstance; + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2,B3,C3)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error) throw new Error(`SUM 公式错误:${result.error}`); + table.changeCellValue(3, 4, result.value, false, false); + table.stateManager.startResizeRow(4, 230, 50); + table.stateManager.updateResizeRow(390, 80); + table.stateManager.endResizeRow(); + window.__sheetRowsBefore = table.rowCount; + table.addRecords([[], []], 2, true); + table.startEditCell(3, 6); + return sheet; + }, + async verify(page) { + // 两行插入必须改变表格结构,原有非空记录不能丢失。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (table.rowCount < window.__sheetRowsBefore + 2) + throw new Error(`Sheet 插行未生效:${window.__sheetRowsBefore} -> ${table.rowCount}`); + if (!Number.isFinite(table.getCellRect(1, 5)?.bounds?.x1)) + throw new Error('Sheet 插行后单元格未布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/copy-paste.mjs b/packages/vtable/__tests__/visual/cases/sheet/copy-paste.mjs new file mode 100644 index 0000000000..83d546f680 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/copy-paste.mjs @@ -0,0 +1,62 @@ +/** + * BugServer case IDs: 6927f3ea215128005c991a9d + * 验证目的:Sheet 公式结果经 copy 事件进入剪贴板,再经 paste 事件写入目标格。 + * 改写:移除菜单与展示插件,保留公式、同一 clipboardData 和事件先后顺序。 + */ +export default { + mount(container) { + // 先把 SUM 结果写回表格,供复制事件读取。 + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', + rowCount: 30, columnCount: 10, data: [[1, 2, 3], [4, 5, 6], [7, 8, 9]], active: true }] + }); + const cell = { sheet: 'sheet1', row: 5, col: 0 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:A4)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error) throw new Error(`Sheet 源公式错误: ${result.error}`); + const table = sheet.getActiveSheet().tableInstance; + table.changeCellValue(0, 5, result.value); + window.__sheetCopySource = result.value; + return sheet; + }, + async exercise(page) { + // 使用一个事件剪贴板对象重放来源的复制和粘贴顺序。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + const element = table.getElement(); + const store = {}; + const clipboardData = { setData(type, value) { store[type] = value; }, + getData(type) { return store[type] || ''; }, clearData(type) { delete store[type]; } }; + Object.defineProperty(clipboardData, 'types', { get: () => Object.keys(store) }); + const clipboardEvent = type => { + const event = new Event(type, { bubbles: true, cancelable: true }); + Object.defineProperty(event, 'clipboardData', { value: clipboardData }); + return event; + }; + const keyEvent = (key, keyCode) => { + const event = document.createEvent('Event'); + event.initEvent('keydown', true, false); + Object.assign(event, { ctrlKey: true, metaKey: true, altKey: true, + which: keyCode, keyCode, key, code: 'Key' + key.toUpperCase() }); + element.focus(); + element.dispatchEvent(event); + }; + table.selectCell(0, 5); + keyEvent('c', 67); + element.dispatchEvent(clipboardEvent('copy')); + window.__sheetCopiedText = store['text/plain'] || store.text || ''; + table.selectCell(1, 5); + keyEvent('v', 86); + element.dispatchEvent(clipboardEvent('paste')); + }); + }, + async verify(page) { + // 剪贴板必须真的收到公式结果,目标格必须真的改变。 + await page.waitForFunction(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + return window.__sheetCopiedText && + String(window.__sheetCopiedText).trim() === String(window.__sheetCopySource) && + String(table.getCellValue(1, 5)).trim() === String(window.__sheetCopySource); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/cross-tab-formula.mjs b/packages/vtable/__tests__/visual/cases/sheet/cross-tab-formula.mjs new file mode 100644 index 0000000000..1200f26b68 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/cross-tab-formula.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 693a765f2f9376005c0328e3 + * 验证目的:第二张 Sheet 的跨表 SUM 范围在第一张 Sheet 显示计算结果。 + * 改写:原范围重复写入 Sheet 名,改为受支持的单表范围;保留中文感叹号归一化条件。 + */ +export default { + mount(container) { + // 两张表使用固定矩阵,Data!A2:A4 的结果应为 11。 + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Summary', rowCount: 20, columnCount: 8, + data: [[1, 2, 3], [4, 5, 6]], active: true }, + { sheetKey: 'sheet2', sheetTitle: 'Data', rowCount: 20, columnCount: 8, + data: [[2, 4, 6], [4, 5, 6], [7, 8, 9], ['A', 'B', 'C']] }] + }); + const cell = { sheet: 'sheet1', row: 5, col: 0 }; + sheet.formulaManager.setCellContent(cell, '=SUM(Data!A2:A4)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error) throw new Error(`跨 Sheet SUM 错误:${result.error}`); + window.__crossSheetValue = result.value; + sheet.getActiveSheet().tableInstance.changeCellValue(0, 5, result.value, false, false); + return sheet; + }, + async verify(page) { + // 公式管理器与可见单元格都应保存第二张表的求和值。 + await page.evaluate(() => { + const sheet = window.__visualTable; + const value = sheet.getActiveSheet().tableInstance.getCellValue(0, 5); + if (window.__crossSheetValue !== 11 || value !== 11) + throw new Error(`跨 Sheet 计算值错误:${window.__crossSheetValue}, ${value}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/formula-auto-fill-copy.mjs b/packages/vtable/__tests__/visual/cases/sheet/formula-auto-fill-copy.mjs new file mode 100644 index 0000000000..f39e1a3f42 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/formula-auto-fill-copy.mjs @@ -0,0 +1,58 @@ +/** + * BugServer case IDs: 692597e7cee9a0005d063c64 + * 验证目的:Sheet 公式结果格拖动填充柄并选择复制填充后,邻列写入相同显示值。 + * 改写:保留来源的 SUM(A2:A4) 和点击、拖动、菜单选择顺序,移除无关主菜单与主题。 + */ +export default { + mount(container) { + // 固定矩阵令 D5 的求和结果与复制到 E5 后的显示值都可预测。 + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 20, columnCount: 10, + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['A', 'B', 'C']], active: true }] + }); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:A4)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error) throw new Error(`源公式错误:${result.error}`); + sheet.getActiveSheet().tableInstance.changeCellValue(3, 4, result.value, false, false); + window.__fillSourceValue = result.value; + return sheet; + }, + async exercise(page) { + // 先选中源单元格,按填充柄实际边界拖到右侧,再点击复制填充菜单。 + const cellCenter = await page.evaluate(() => { + const bounds = window.__visualTable.getActiveSheet().tableInstance.scenegraph.getCell(3, 4).globalAABBBounds; + const canvas = window.__visualTable.getActiveSheet().tableInstance.canvas.getBoundingClientRect(); + return { x: canvas.x + (bounds.x1 + bounds.x2) / 2, + y: canvas.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.click(cellCenter.x, cellCenter.y); + const points = await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + const selected = [...table.scenegraph.selectedRangeComponents.values()][0]; + const handle = selected?.fillhandle?.globalAABBBounds; + if (!handle) throw new Error('Sheet 填充柄未显示'); + const target = table.scenegraph.getCell(4, 4).globalAABBBounds; + const canvas = table.canvas.getBoundingClientRect(); + return { start: { x: canvas.x + (handle.x1 + handle.x2) / 2, + y: canvas.y + (handle.y1 + handle.y2) / 2 }, + end: { x: canvas.x + target.x2 - 8, y: canvas.y + target.y2 - 8 } }; + }); + await page.mouse.move(points.start.x, points.start.y); + await page.mouse.down(); + await page.mouse.move(points.end.x, points.end.y, { steps: 10 }); + await page.mouse.up(); + await page.locator('.vtable__menu-element__item').filter({ hasText: '复制填充' }).click(); + }, + async verify(page) { + // 当前复制填充行为将源格显示值 11 写到相邻单元格,源格仍为 11。 + await page.evaluate(() => { + const sheet = window.__visualTable; + const table = sheet.getActiveSheet().tableInstance; + if (window.__fillSourceValue !== 11 || table.getCellValue(3, 4) !== 11 || + table.getCellValue(4, 4) !== 11) + throw new Error(`公式自动填充结果错误:${table.getCellValue(3, 4)}, ${table.getCellValue(4, 4)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/formula-edit.mjs b/packages/vtable/__tests__/visual/cases/sheet/formula-edit.mjs new file mode 100644 index 0000000000..2a2924c120 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/formula-edit.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 690076c72ab33400b4abb33a + * 验证目的:Sheet 跨区域 SUM 公式回填后进入单元格编辑状态。 + * 改写:保留公式与编辑顺序,移除与此目的无关的菜单和插件配置。 + */ +export default { + mount(container) { + // 固定数据让 SUM(A2:C2,B3,C3) 的结果可预测。 + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 20, columnCount: 10, + columns: [{ title: 'Name', sort: true, width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9]], active: true }] + }); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2,B3,C3)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error) throw new Error(`SUM 公式错误:${result.error}`); + window.__formulaResult = result.value; + const table = sheet.getActiveSheet().tableInstance; + table.changeCellValue(3, 4, result.value, false, false); + table.startEditCell(3, 4); + return sheet; + }, + async verify(page) { + // 公式结果应保存在表格对应单元格中。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (!Number.isFinite(window.__formulaResult) || table.getCellValue(3, 4) !== window.__formulaResult) + throw new Error(`公式结果错误:${window.__formulaResult}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/update-option.mjs b/packages/vtable/__tests__/visual/cases/sheet/update-option.mjs new file mode 100644 index 0000000000..ba1059758a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/update-option.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 6980594c7a558400611ce045 + * 验证目的:Sheet 的全量 updateOption 删除旧页、新增并激活新页、更新现有页数据。 + * 改写:删去与更新无关的菜单和插件,保留两个工作表与全量更新路径。 + */ +export default { + mount(container) { + // 从两个工作表切换为新页加更新后的第二页,重建公式依赖路径也会执行。 + const sheet = new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, sheets: [ + { sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 20, columnCount: 10, + data: [[1, 2, 3], [4, 5, 6]], active: true }, + { sheetKey: 'sheet2', sheetTitle: 'Sheet 2', rowCount: 20, columnCount: 10, + data: [[2, 4, 6], [4, 5, 6]] } + ] + }); + sheet.updateOption({ showSheetTab: false, defaultRowHeight: 25, defaultColWidth: 100, + sheets: [ + { sheetKey: 'sheet12', sheetTitle: 'Sheet 12', rowCount: 20, columnCount: 10, + data: [[111, 211, 311], [4, 5, 6]], active: true }, + { sheetKey: 'sheet2', sheetTitle: 'Sheet 2', rowCount: 20, columnCount: 10, + data: [[222, 422, 622], [4, 5, 6]] } + ] }); + return sheet; + }, + async verify(page) { + // 旧页应删除,新增页激活,第二页数据同步为新值。 + await page.evaluate(() => { + const sheet = window.__visualTable; + if (sheet.getWorkSheetInstance('sheet1') || sheet.getActiveSheet()?.getKey() !== 'sheet12' || + !sheet.getWorkSheetInstance('sheet2') || !sheet.getActiveSheet().tableInstance) + throw new Error('Sheet 全量更新后的页结构错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sort/initial-desc.mjs b/packages/vtable/__tests__/visual/cases/sort/initial-desc.mjs new file mode 100644 index 0000000000..e5f8312f2c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sort/initial-desc.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 64745bc55d221c008666ee23 + * 验证目的:setRecords 的初始降序状态与自定义比较器共同排序。 + * 改写:缩减不影响排序的展示列,保留 name 排序事件的拦截回调。 + */ +export default { + mount(container) { + // 来源按 id 降序设置记录,并阻止 name 列的排序点击。 + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, + fieldFormat: record => `Completed ${record.progress}%` }, + { field: 'id', title: 'ID', width: 100, + sort: (a, b, order) => order === 'desc' ? b - a : a - b }, + { field: 'name', title: 'Name', width: 150, sort: true } + ], + records: [], widthMode: 'standard', allowFrozenColCount: 2 + }); + table.setRecords([ + { id: 1, progress: 100, name: 'A' }, { id: 2, progress: 80, name: 'B' }, + { id: 3, progress: 1, name: 'C' }, { id: 4, progress: 55, name: 'D' }, + { id: 5, progress: 28, name: 'E' } + ], { field: 'id', order: 'desc' }); + table.on('sort_click', args => { if (args.field === 'name') return false; }); + return table; + }, + async verify(page) { + // 直接检查可见首尾记录顺序。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellOriginValue(1, 1) !== 5 || table.getCellOriginValue(1, 5) !== 1) + throw new Error('初始降序未生效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sort/initial-multiple-state.mjs b/packages/vtable/__tests__/visual/cases/sort/initial-multiple-state.mjs new file mode 100644 index 0000000000..b26784b236 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sort/initial-multiple-state.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 66cd83fe5e11d900c8f0e96b + * 验证目的:先设置双字段降序,再 setRecords 后仍按两个字段排序。 + * 改写:将来源的人员字段改为编号与代号,保留两个排序键的并列数据。 + */ +export default { + mount(container) { + // 同一 score 内的 code 次序使第二排序键是否执行可观察。 + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'score', title: 'Score', sort: true, width: 140 }, + { field: 'code', title: 'Code', sort: true, width: 140 } + ], + multipleSort: true, + sortState: [{ field: 'score', order: 'desc' }, { field: 'code', order: 'desc' }], + widthMode: 'standard' + }); + table.setRecords([ + { score: 1, code: 'A' }, { score: 3, code: 'B' }, + { score: 3, code: 'C' }, { score: 2, code: 'D' } + ]); + return table; + }, + async verify(page) { + // 首字段降序后,同分组中的 C 必须排在 B 前。 + await page.evaluate(() => { + const table = window.__visualTable; + const codes = [1, 2, 3, 4].map(row => table.getCellValue(1, row)); + if (codes.join(',') !== 'C,B,D,A' || table.sortState?.length !== 2) + throw new Error(`初始复合排序错误:${JSON.stringify({ codes, sortState: table.sortState })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sort/multiple-header-click.mjs b/packages/vtable/__tests__/visual/cases/sort/multiple-header-click.mjs new file mode 100644 index 0000000000..9719b754e4 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sort/multiple-header-click.mjs @@ -0,0 +1,50 @@ +/** + * BugServer case IDs: 66cd81605e11d900c8f0e968 + * 验证目的:multipleSort 模式依次点击两个排序表头后保留两个排序状态。 + * 改写:保留重复 sortID 和两个点击动作,缩减无关格式化字段。 + */ +export default { + mount(container) { + // 重复 sortID 让第二排序字段有机会决定相邻记录的顺序。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'sortID', title: 'Sort ID', width: 150, sort: true }, + { field: 'name', title: 'Name', width: 150, sort: true }], + records: [{ id: 1, sortID: 6, name: 'a' }, { id: 2, sortID: 4, name: 'd' }, + { id: 3, sortID: 4, name: 'c' }, { id: 4, sortID: 2, name: 'a' }, + { id: 5, sortID: 3, name: 'b' }, { id: 6, sortID: 5, name: 'c' }], + multipleSort: true, widthMode: 'standard' + }); + }, + async exercise(page) { + // 点击两个真实表头排序图标,而不是直接写入 sortState。 + for (const col of [1, 2]) { + const point = await page.evaluate(col => { + // 图标位于标题内容右侧;按场景图实际边界定位,避免把列右边界当作图标。 + const cell = window.__visualTable.scenegraph.getCell(col, 0); + const stack = [cell]; + let icon; + while (stack.length && !icon) { + const mark = stack.pop(); + if (mark.attribute?.funcType === 'sort') icon = mark; + else stack.push(...(mark.children ?? [])); + } + if (!icon) throw new Error(`第 ${col} 列排序图标未渲染`); + const bounds = icon.globalAABBBounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }, col); + await page.mouse.move(point.x, point.y); + await page.mouse.click(point.x, point.y); + } + }, + async verify(page) { + // 两个真实点击后排序状态必须同时保留两个字段。 + await page.evaluate(() => { + const states = window.__visualTable.sortState; + if (!Array.isArray(states) || states.length !== 2 || + !states.some(state => state.field === 'sortID') || !states.some(state => state.field === 'name')) + throw new Error(`复合排序状态异常: ${JSON.stringify(states)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sort/update-state.mjs b/packages/vtable/__tests__/visual/cases/sort/update-state.mjs new file mode 100644 index 0000000000..a95d43cedd --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sort/update-state.mjs @@ -0,0 +1,24 @@ +/** + * BugServer case IDs: 65c086ce97cc3d008de5b482 + * 验证目的:setRecords 降序后通过 updateSortState 切换到升序。 + * 改写:仅保留排序列与固定数值,避免重复的展示字段。 + */ +export default { + mount(container) { + // 两次排序调用顺序与来源一致,结果首行应为最小值。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, sort: true }, + { field: 'name', title: 'Name', width: 150 }], widthMode: 'standard' + }); + table.setRecords([{ progress: 100, name: 'A' }, { progress: 80, name: 'B' }, + { progress: 1, name: 'C' }], { field: 'progress', order: 'desc' }); + table.updateSortState({ field: 'progress', order: 'asc' }); + return table; + }, + async verify(page) { + // 最终排序后的第一条记录须是数值 1。 + await page.evaluate(() => { + if (window.__visualTable.getCellValue(0, 1) !== 1) throw new Error('排序状态未更新'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/style/border-clip-direction.mjs b/packages/vtable/__tests__/visual/cases/style/border-clip-direction.mjs new file mode 100644 index 0000000000..c8fc2afe5d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/style/border-clip-direction.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 66e28a3d0eae0a00f267b41e + * 验证目的:cellBorderClipDirection=bottom-right 与内边框同用时边线不断裂。 + * 改写:删除展示性说明,保留四边红色单元格边框和无外框条件。 + */ +export default { + mount(container) { + // 相邻多行让边框裁剪方向在截图中有可比差异。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, + fieldFormat: record => `${record.progress}%`, style: { textAlign: 'center', borderColor: ['red', 'red', 'red', 'red'] } }], + records: [100, 80, 1, 55, 28].map(progress => ({ progress })), + widthMode: 'standard', theme: { + frameStyle: { borderLineWidth: 0 }, cellInnerBorder: true, + cellBorderClipDirection: 'bottom-right' + } + }); + }, + async verify(page) { + // 最小值和最大值进入两端单元格,边线交给截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== '100%' || table.getCellValue(0, 5) !== '28%') + throw new Error('裁剪边框测试数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/style/dashed-border.mjs b/packages/vtable/__tests__/visual/cases/style/dashed-border.mjs new file mode 100644 index 0000000000..1940231eb0 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/style/dashed-border.mjs @@ -0,0 +1,23 @@ +/** + * BugServer case IDs: 65c1d09f97cc3d008de5b4bb + * 验证目的:单元格边框颜色数组与虚线样式同时绘制。 + * 改写:缩小记录和无关列,保留红字、双色边框和 [4,4] 线型。 + */ +export default { + mount(container) { + // 两条记录足以让虚线与相邻单元格边框进入截图。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, + style: { color: 'red', borderColor: ['red', 'green'], borderLineDash: [4, 4] } }, + { field: 'name', title: 'Name', width: 150 }], + records: [{ progress: 100, name: 'A' }, { progress: 80, name: 'B' }] + }); + }, + async verify(page) { + // 读取实际单元格样式,确认虚线配置没有被主题覆盖。 + await page.evaluate(() => { + const dash = window.__visualTable.getCellStyle(0, 1).borderLineDash; + if (!Array.isArray(dash) || dash.join(',') !== '4,4') throw new Error('虚线边框配置缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/style/underline.mjs b/packages/vtable/__tests__/visual/cases/style/underline.mjs new file mode 100644 index 0000000000..c0e4e60fca --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/style/underline.mjs @@ -0,0 +1,34 @@ +/** + * BugServer case IDs: 65e6dd18603de700d1d8ba05 + * 验证目的:普通、虚线和带偏移下划线与虚线边框共存。 + * 改写:保留四列差异及换行记录,修正来源 widthMode 拼写错误。 + */ +export default { + mount(container) { + // 同一行配置多种下划线参数,便于视觉比较细节。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, + style: { underline: true, color: 'red', borderColor: ['red', 'green'], borderLineDash: [4, 8] } }, + { field: 'id', title: 'ID', width: 100, + style: { underline: true, underlineDash: [4, 1], underlineOffset: 10, + color: 'red', borderColor: ['red', 'green'], borderLineDash: [8, 8] } }, + { field: 'note', title: 'Note', width: 150, + style: { autoWrapText: true, underline: true, underlineDash: [4, 1], underlineOffset: 10, + color: 'red', borderColor: ['red', 'green'], borderLineDash: [4, 8] } }, + { field: 'name', title: 'Name', width: 150, + style: { autoWrapText: true, underline: true, color: 'red', borderColor: ['red', 'green'], borderLineDash: [4, 8] } }], + records: [{ progress: 100, id: 1, note: 'Line 1\nLine 2', name: 'A\nB' }, + { progress: 80, id: 2, note: 'Short', name: 'C' }], + widthMode: 'standard', heightMode: 'autoHeight', enableLineBreak: true + }); + }, + async verify(page) { + // 四列样式都已配置,文字边界仍通过截图判定。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 4 || table.getCellValue(2, 1) !== 'Line 1\nLine 2' || + table.options.columns[1].style.underlineOffset !== 10) + throw new Error('下划线样式场景无效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/table/list-basic.mjs b/packages/vtable/__tests__/visual/cases/table/list-basic.mjs new file mode 100644 index 0000000000..eb6dd00c49 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/table/list-basic.mjs @@ -0,0 +1,24 @@ +/** + * 验证目的:列表表头和固定数据能正确创建、绘制与读取。 + * 来源:VTable 公共 ListTable API 独立样例。 + * 覆盖边界:不测试排序、编辑或虚拟滚动。 + */ +export default { + mount(container) { + // 固定记录与列配置,供双侧构建使用完全相同的输入。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 150 }, { field: 'value', title: 'Value', width: 150 }], + records: [{ name: 'Alpha', value: 10 }, { name: 'Beta', value: 20 }] + }); + }, + async verify(page) { + // 同时检查数据语义和可见单元格位置,图片比较负责像素布局。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== 'Alpha' || table.getCellValue(1, 2) !== 20) + throw new Error('列表数据不正确'); + const rect = table.getCellRect(0, 1)?.bounds; + if (!rect || rect.x2 <= rect.x1 || rect.y2 <= rect.y1) throw new Error('没有有效单元格布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/table/list-select-cell.mjs b/packages/vtable/__tests__/visual/cases/table/list-select-cell.mjs new file mode 100644 index 0000000000..95c6044f27 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/table/list-select-cell.mjs @@ -0,0 +1,30 @@ +/** + * 验证目的:鼠标点击数据单元格后选择状态发生真实变化。 + * 来源:VTable 公共 ListTable API 独立样例。 + * 覆盖边界:不测试多选、拖选或键盘导航。 + */ +export default { + mount(container) { + // 创建两行数据,确保交互目标不依赖浏览器外部资源。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 150 }, { field: 'value', title: 'Value', width: 150 }], + records: [{ name: 'Alpha', value: 10 }, { name: 'Beta', value: 20 }] + }); + }, + async exercise(page) { + // 根据公开单元格矩形定位目标,避免录制坐标在宿主尺寸变化后失效。 + const point = await page.evaluate(() => { + const bounds = window.__visualTable.getCellRect(1, 2).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 禁止仅凭截图或点击完成来宣称交互已生效。 + await page.waitForFunction(() => { + const range = window.__visualTable.getSelectedCellRanges()[0]; + return range?.start.col === 1 && range?.start.row === 2 && range?.end.col === 1 && range?.end.row === 2; + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/theme/arco.mjs b/packages/vtable/__tests__/visual/cases/theme/arco.mjs new file mode 100644 index 0000000000..5b8319ca66 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/theme/arco.mjs @@ -0,0 +1,29 @@ +/** + * BugServer case IDs: 647460d15d221c008666ee29 + * 验证目的:ARCO 主题与交叉悬停模式、自动行高共同渲染。 + * 改写:使用通用固定记录,保留主题和相关布局配置。 + */ +export default { + mount(container) { + // 主题配置由当前侧 VTable bundle 提供,避免外部资源。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }], + showPin: true, widthMode: 'standard', allowFrozenColCount: 2, + theme: window.VTable.themes.ARCO, + hover: { highlightMode: 'cross', disableHeaderHover: true }, + heightMode: 'autoHeight', autoWrapText: true + }); + }, + async verify(page) { + // 验证主题表格完成数据渲染,颜色差异由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(2, 1) !== 'A') throw new Error('ARCO 主题表格数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/theme/dark-icons.mjs b/packages/vtable/__tests__/visual/cases/theme/dark-icons.mjs new file mode 100644 index 0000000000..1f319b5662 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/theme/dark-icons.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 66f5028c885776011c598a60 + * 验证目的:DARK 主题下的排序、冻结和悬停图标保持可见。 + * 改写:保留 DARK、两列冻结、cross 悬停及自动高度,缩减展示字段。 + */ +export default { + mount(container) { + // 深色主题和图标相关配置保持在同一固定场景中。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100, sort: true }, + { field: 'name', title: 'Name', width: 150, sort: true }], + records: [100, 80, 1, 55, 28].map((progress, i) => ({ progress, id: i + 1, name: `Name ${i + 1}` })), + showPin: true, widthMode: 'standard', frozenColCount: 2, allowFrozenColCount: 3, + theme: window.VTable.themes.DARK, hover: { highlightMode: 'cross', disableHeaderHover: true }, + heightMode: 'autoHeight', autoWrapText: true + }); + }, + async verify(page) { + // 深色主题用例必须保留两列数据和冻结配置。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== 100 || table.frozenColCount !== 2) + throw new Error('深色主题冻结列缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/theme/update-theme.mjs b/packages/vtable/__tests__/visual/cases/theme/update-theme.mjs new file mode 100644 index 0000000000..518577b329 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/theme/update-theme.mjs @@ -0,0 +1,27 @@ +/** + * BugServer case IDs: 6567f9cc69022a32a0625120 + * 验证目的:创建 ARCO 主题列表后 updateTheme 立即更新画布底色。 + * 改写:缩减展示列,保留 cross 悬停、自动行高与 ARCO extends 更新顺序。 + */ +export default { + mount(container) { + // 先创建 ARCO,再覆盖 underlayBackgroundColor,避免仅测试初始主题。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100, sort: true }, { field: 'name', title: 'Name', width: 150 }], + records: [100, 80, 1, 55, 28].map((progress, i) => ({ progress, id: i + 1, name: `Name ${i + 1}` })), + theme: window.VTable.themes.ARCO, hover: { highlightMode: 'cross', disableHeaderHover: true }, + widthMode: 'standard', heightMode: 'autoHeight', autoWrapText: true + }); + table.updateTheme(window.VTable.themes.ARCO.extends({ underlayBackgroundColor: 'red' })); + return table; + }, + async verify(page) { + // 更新后数据仍可访问且主题覆盖被表格接收;具体底色由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellValue(0, 1) !== 100 || table.theme.underlayBackgroundColor !== 'red') + throw new Error('updateTheme 未应用底色'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/transpose/only-body-auto-width.mjs b/packages/vtable/__tests__/visual/cases/transpose/only-body-auto-width.mjs new file mode 100644 index 0000000000..5ddfe5b044 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/transpose/only-body-auto-width.mjs @@ -0,0 +1,48 @@ +/** + * BugServer case IDs: 64b78beef1af57b472231cac, 65dc4029db5fe000ad96fd7f + * 验证目的:转置表的 only-body 自动列宽不被很长的行头标题撑大。 + * 改写:来源的人员字段和图标替换为两个匿名字段与短记录。 + */ +export default { + mount(container) { + // 标准模式与 only-body 模式共享长标题,用实测行头列宽比较。 + container.style.width = '800px'; + container.style.height = '320px'; + container.style.display = 'grid'; + container.style.gridTemplateColumns = '1fr 1fr'; + const options = { + columns: [ + { field: 'a', title: 'A very long header label for the first field', width: 'auto' }, + { field: 'b', title: 'Another long header label', width: 'auto' } + ], + records: [{ a: 'X', b: 'Y' }, { a: 'M', b: 'N' }], + transpose: true, widthMode: 'autoWidth', defaultHeaderColWidth: 80 + }; + const tables = ['normal', 'only-body'].map(columnWidthComputeMode => { + const host = document.createElement('div'); + host.style.cssText = 'width:390px;height:310px'; + container.append(host); + return new window.VTable.ListTable(host, { ...options, columnWidthComputeMode }); + }); + return { + tables, + async renderAsync() { + // 等待转置表自动宽度计算完成。 + await Promise.all(tables.map(table => table.renderAsync?.())); + }, + release() { + // 两张对照表分别释放。 + tables.forEach(table => table.release()); + } + }; + }, + async verify(page) { + // only-body 的首列应保持默认行头宽度,normal 则受长标题撑宽。 + await page.evaluate(() => { + const [normal, body] = window.__visualTable.tables; + const widths = [normal.getColWidth(0), body.getColWidth(0)]; + if (widths[0] <= widths[1] + 80 || widths[1] > 100) + throw new Error(`转置 only-body 列宽异常:${JSON.stringify(widths)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/transpose/theme-header.mjs b/packages/vtable/__tests__/visual/cases/transpose/theme-header.mjs new file mode 100644 index 0000000000..6a08a6a39d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/transpose/theme-header.mjs @@ -0,0 +1,39 @@ +/** + * BugServer case IDs: 65d599b29c176100a02dd0a4 + * 验证目的:转置列表中分组表头和扩展主题边框共同绘制。 + * 改写:人物联系方式替换为固定通用文本,保留转置、嵌套列及主题扩展结构。 + */ +export default { + mount(container) { + // 使用三个公开示例字段和多行记录,避免私人联系方式进入仓库。 + return new window.VTable.ListTable(container, { + records: [ + { id: 1, first: 'A', last: 'One', city: 'North' }, + { id: 2, first: 'B', last: 'Two', city: 'South' }, + { id: 3, first: 'C', last: 'Three', city: 'East' } + ], + columns: [ + { field: 'id', title: 'ID', sort: true, width: 'auto' }, + { title: 'Full name', columns: [ + { field: 'first', title: 'First name' }, { field: 'last', title: 'Last name' } + ] }, + { field: 'city', title: 'City' } + ], + widthMode: 'standard', transpose: true, dragHeaderMode: 'all', limitMinWidth: 20, + theme: window.VTable.themes.DEFAULT.extends({ + headerStyle: { color: 'red', frameStyle: { borderColor: 'red', borderLineWidth: 2 } } + }) + }); + }, + async verify(page) { + // 转置后列数随记录数增长,且表格保留原有字段值。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellValue(col, row)); + if (!table.options.transpose || !values.includes('Three') || !values.includes('South')) + throw new Error('转置数据或布局缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/transpose/update-option-off.mjs b/packages/vtable/__tests__/visual/cases/transpose/update-option-off.mjs new file mode 100644 index 0000000000..8a0e064ee5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/transpose/update-option-off.mjs @@ -0,0 +1,26 @@ +/** + * BugServer case IDs: 65a60e2cc2cd3f0ae258d5e5 + * 验证目的:先以转置模式设定 100 条记录,再用 updateOption 关闭转置。 + * 改写:保留操作顺序和记录规模,移除无关复杂 SVG 与日期字段。 + */ +export default { + mount(container) { + // 转置状态下先设置记录,再复用配置对象切回普通表格。 + const option = { columns: [{ field: 'progress', title: 'Progress', width: 120 }, + { field: 'id', title: 'ID', width: 100 }, { field: 'name', title: 'Name', width: 150 }], + widthMode: 'standard', transpose: true, hover: { highlightMode: 'cross' } }; + const table = new window.VTable.ListTable(container, option); + table.setRecords(Array.from({ length: 100 }, (_, i) => ({ progress: i, id: i + 1, name: `Name ${i + 1}` }))); + option.transpose = false; + table.updateOption(option); + return table; + }, + async verify(page) { + // 更新后必须恢复三列一百行的普通表格。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.colCount !== 3 || table.rowCount !== 101 || table.getCellValue(1, 1) !== 1) + throw new Error('updateOption 未关闭转置'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/checkbox-add-record.mjs b/packages/vtable/__tests__/visual/cases/tree/checkbox-add-record.mjs new file mode 100644 index 0000000000..f997814af6 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/checkbox-add-record.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 6889e5b0b485f100aabeadee + * 验证目的:树形列表的行序号复选状态在头部插入记录后仍可见。 + * 改写:商品层级与金额换成通用节点,保留三级树、懒加载节点与 addRecord。 + */ +export default { + mount(container) { + // 先设置原有复选状态,再在根记录索引 0 插入空记录。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', cellType: 'checkbox', tree: true, title: 'Group', width: 190 }, + { field: 'value', title: 'Value', width: 120 }], + records: [{ name: 'Group A', value: 100, children: [ + { name: 'A1', value: 60, children: [{ name: 'A1a', value: 30 }, { name: 'A1b', value: 30 }] }, + { name: 'A2', value: 40 } + ] }, { name: 'Group B', value: 80, children: [{ name: 'B1', value: 80 }] }, + { name: 'Lazy group', value: 20, children: true }], + hierarchyIndent: 20, hierarchyExpandLevel: 2, enableCheckboxCascade: false, + // 行序号列采用无文字复选框,以保持原来源的状态迁移条件。 + rowSeriesNumber: { width: 50, cellType: 'checkbox', format: () => '' }, + select: { disableDragSelect: true }, theme: window.VTable.themes.BRIGHT + }); + table.setCellCheckboxState(0, 1, true); + table.setCellCheckboxState(0, 2, true); + table.setCellCheckboxState(0, 5, true); + window.__treeRowsBefore = table.rowCount; + table.addRecord({}, 0); + return table; + }, + async verify(page) { + // 新增根记录后行数应增加,原已选复选框仍有可见状态。 + await page.evaluate(() => { + const table = window.__visualTable; + let checked = 0; + for (let row = 1; row < table.rowCount; row++) + if (table.getCellCheckboxState(0, row) === true) checked++; + if (table.rowCount <= window.__treeRowsBefore || checked < 1) + throw new Error(`树记录插入后复选状态错误:rows=${table.rowCount}, checked=${checked}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/checkbox-delete-record.mjs b/packages/vtable/__tests__/visual/cases/tree/checkbox-delete-record.mjs new file mode 100644 index 0000000000..2cb15ee129 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/checkbox-delete-record.mjs @@ -0,0 +1,43 @@ +/** + * BugServer case IDs: 6889e710e565f800a58eb402 + * 验证目的:树形列表同时删除根节点及子节点后,行序号复选状态与树结构仍可用。 + * 改写:用通用节点替换商品和金额文字,保留 deleteRecords 的混合路径参数。 + */ +export default { + mount(container) { + // 多层树里预设复选状态,然后删除第一个根和第二根的首个子节点。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', cellType: 'checkbox', tree: true, title: 'Group', width: 190 }, + { field: 'value', title: 'Value', width: 120 }], + records: [{ name: 'Group A', value: 100, children: [ + { name: 'A1', value: 60, children: [{ name: 'A1a', value: 30 }, { name: 'A1b', value: 30 }] }, + { name: 'A2', value: 40 } + ] }, { name: 'Group B', value: 80, children: [ + { name: 'B1', value: 40 }, { name: 'B2', value: 40 } + ] }, { name: 'Group C', value: 70, children: [{ name: 'C1', value: 70 }] }, + { name: 'Lazy group', value: 20, children: true }], + hierarchyIndent: 20, hierarchyExpandLevel: 2, enableCheckboxCascade: false, + // 行序号空文字复选框保留来源的状态场景。 + rowSeriesNumber: { width: 50, cellType: 'checkbox', format: () => '' }, + select: { disableDragSelect: true }, theme: window.VTable.themes.BRIGHT + }); + table.setCellCheckboxState(1, 3, true); + table.setCellCheckboxState(0, 1, true); + table.setCellCheckboxState(0, 2, true); + table.setCellCheckboxState(0, 6, true); + window.__treeRowsBefore = table.rowCount; + table.deleteRecords([0, [1, 0]]); + return table; + }, + async verify(page) { + // 混合层级删除应缩短可见树,剩余行仍可读取复选状态。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.rowCount >= window.__treeRowsBefore || !table.records.some(record => record.name === 'Group C')) + throw new Error(`树记录删除失败:${window.__treeRowsBefore} -> ${table.rowCount}`); + const states = Array.from({ length: table.rowCount - 1 }, (_, index) => table.getCellCheckboxState(0, index + 1)); + if (!states.some(state => state === true)) + throw new Error(`删除后已选行丢失:${JSON.stringify(states)};records=${JSON.stringify(table.records)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/checkbox-record-index-clear.mjs b/packages/vtable/__tests__/visual/cases/tree/checkbox-record-index-clear.mjs new file mode 100644 index 0000000000..6ebf296f12 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/checkbox-record-index-clear.mjs @@ -0,0 +1,59 @@ +/** + * BugServer case IDs: 6a68957b3dd664005e729649 + * 验证目的:折叠树的隐藏子记录可按原始索引取消勾选,再清空整列复选状态。 + * 改写:来源的项目人员改为匿名分组,保留两次点击触发对应 API。 + */ +export default { + mount(container) { + // 隐藏子节点保持初始选中,两个普通操作列单元格触发状态 API。 + const table = new window.VTable.ListTable(container, { + columns: [ + { field: 'item', title: 'Item', tree: true, cellType: 'checkbox', headerType: 'checkbox', width: 230 }, + { field: 'action', title: 'Action', width: 260 } + ], + records: [ + { item: { text: 'Group A', checked: true }, action: 'Uncheck hidden child', + hierarchyState: 'collapse', children: [ + { item: { text: 'Child A1', checked: true }, action: 'Hidden' }, + { item: { text: 'Child A2', checked: true }, action: 'Hidden' } + ] }, + { item: { text: 'Group B', checked: true }, action: 'Clear all' } + ], + enableCheckboxCascade: false, enableHeaderCheckboxCascade: false, + hierarchyIndent: 20, defaultRowHeight: 38 + }); + table.on('click_cell', ({ col, row }) => { + // 用户点击操作列后分别调用隐藏记录索引和整列清除 API。 + if (col === 1 && row === 1) table.setCellCheckboxStateByRecordIndex([0, 0], 'item', false); + if (col === 1 && row === 2) table.clearAllCheckboxState('item'); + }); + return table; + }, + async exercise(page) { + // 第一次点击后记录隐藏子节点状态,再点击第二行清除全部状态。 + const points = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [1, 2].map(row => { + const b = table.getCellRect(1, row).bounds; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + }); + await page.mouse.click(points[0].x, points[0].y); + await page.evaluate(() => { + // 使用原始树路径检查隐藏子节点,不依赖它是否出现在当前可视行。 + const checked = window.__visualTable.stateManager.checkedState; + if (checked.get('0,0')?.item !== false || checked.get('0')?.item !== true) + throw new Error(`隐藏子节点状态异常:${JSON.stringify([...checked])}`); + }); + await page.mouse.click(points[1].x, points[1].y); + }, + async verify(page) { + // 两次点击后,所有树节点的复选状态都应已清空。 + await page.evaluate(() => { + const checked = window.__visualTable.stateManager.checkedState; + if ([...checked.values()].some(state => state.item === true)) + throw new Error(`整列复选状态未清空:${JSON.stringify([...checked])}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/checkbox-set-state.mjs b/packages/vtable/__tests__/visual/cases/tree/checkbox-set-state.mjs new file mode 100644 index 0000000000..0c8899bcd0 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/checkbox-set-state.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 6889ea68eb9ae000b36719b2 + * 验证目的:树列表中对第三级节点设置复选状态,且不级联到父节点。 + * 改写:分类与数值改为通用数据,保留树层级、行序号复选框与 setCellCheckboxState(1,3,true)。 + */ +export default { + mount(container) { + // 展开两层树并关闭级联,再设置原始位置的子节点复选框。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'category', cellType: 'checkbox', tree: true, title: 'Category', width: 190 }, + { field: 'amount', title: 'Amount', width: 120 }], + records: [{ category: 'Group A', amount: 100, children: [ + { category: 'Subgroup A1', amount: 60, children: [ + { category: 'Leaf A', amount: 30 }, { category: 'Leaf B', amount: 30 }] }, + { category: 'Subgroup A2', amount: 40 } ] }, + { category: 'Group B', amount: 80, children: [{ category: 'Subgroup B1', amount: 80 }] }, + { category: 'Lazy group', amount: 20, children: true }], + hierarchyIndent: 20, hierarchyExpandLevel: 2, enableCheckboxCascade: false, + rowSeriesNumber: { width: 50, cellType: 'checkbox', format: () => '' }, + select: { disableDragSelect: true }, theme: window.VTable.themes.BRIGHT + }); + table.setCellCheckboxState(1, 3, true); + return table; + }, + async verify(page) { + // 第三级节点已选中,未发生向父节点级联。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellCheckboxState(1, 3) !== true || table.getCellCheckboxState(1, 2) === true) + throw new Error('树节点复选状态或级联不符合预期'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/filter-clear-lazy.mjs b/packages/vtable/__tests__/visual/cases/tree/filter-clear-lazy.mjs new file mode 100644 index 0000000000..1ac4b7e5eb --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/filter-clear-lazy.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 66053ddec302f600a46921a1, 66053eb3a8fccc00acd37033 + * 验证目的:树形列表的过滤、懒加载子项和清除过滤依次保持正确层级。 + * 改写:商品层级替换为匿名节点,保留高低数值过滤及清除动作。 + */ +export default { + mount(container) { + // 首个父项的子节点由展开事件提供,另一个父项被高分过滤排除。 + container.style.height = '400px'; + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'label', title: 'Node', width: 220, tree: true }, + { field: 'score', title: 'Score', width: 120 }], + records: [{ label: 'Group A', score: 90, children: true }, + { label: 'Group B', score: 10, children: [{ label: 'B1', score: 5 }] }], + hierarchyExpandLevel: 1, hierarchyIndent: 20 + }); + table.on(window.VTable.ListTable.EVENT_TYPE.TREE_HIERARCHY_STATE_CHANGE, args => { + if (args.hierarchyState === window.VTable.TYPES.HierarchyState.expand && + !Array.isArray(args.originData.children)) + table.setRecordChildren([{ label: 'A1', score: 70 }, + { label: 'A2', score: 20 }], args.col, args.row); + }); + return table; + }, + async exercise(page) { + // 先确认过滤减少可见行,再展开留下的懒加载节点并清除规则。 + await page.evaluate(() => { + const table = window.__visualTable; + window.__treeRowsBefore = table.rowCount; + table.updateFilterRules([{ filterFunc: record => record.score > 50 }]); + window.__treeRowsFiltered = table.rowCount; + }); + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(0, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 23, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + await page.evaluate(() => window.__visualTable.updateFilterRules()); + }, + async verify(page) { + // 清除后原节点和懒加载子项均可见,行数回升。 + await page.evaluate(() => { + const table = window.__visualTable; + const labels = Array.from({ length: table.rowCount }, (_, row) => table.getCellValue(0, row)); + if (window.__treeRowsFiltered >= window.__treeRowsBefore || + !labels.includes('Group B') || !labels.includes('A1')) + throw new Error(`树过滤清除或懒加载失败:${JSON.stringify(labels)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/lazy-record-children.mjs b/packages/vtable/__tests__/visual/cases/tree/lazy-record-children.mjs new file mode 100644 index 0000000000..564bb064f8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/lazy-record-children.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 656701ec4c3611faee9b19db + * 验证目的:点击懒加载树节点后,在层级事件中 setRecordChildren 并显示新子节点。 + * 改写:商品分类与金额替换成通用分组,保留 children:true 与真实展开点击。 + */ +export default { + mount(container) { + // 初始懒加载节点无数组 children,展开事件负责补入固定子记录。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Group', tree: true, width: 200, sort: true }, + { field: 'value', title: 'Value', width: 120, sort: true }], + records: [{ name: 'Group A', value: 10, children: [ + { name: 'A1', value: 5 }, { name: 'A2', value: 5 } + ] }, { name: 'Lazy group', value: 20, children: true }, + { name: 'Group B', value: 30, children: [{ name: 'B1', value: 30 }] }], + hierarchyIndent: 20, hierarchyExpandLevel: 2, allowFrozenColCount: 2, + showPin: true, theme: window.VTable.themes.BRIGHT, defaultRowHeight: 32 + }); + table.on(window.VTable.ListTable.EVENT_TYPE.TREE_HIERARCHY_STATE_CHANGE, args => { + // 仅对首次展开的占位节点补入子行,避免重复展开时覆盖数据。 + if (args.hierarchyState !== window.VTable.TYPES.HierarchyState.expand || + Array.isArray(args.originData.children)) return; + table.setRecordChildren([{ name: 'Lazy child A', value: 7 }, + { name: 'Lazy child B', value: 13 }], args.col, args.row); + }); + return table; + }, + async exercise(page) { + // 用单元格位置定位懒加载行的层级图标,避免依赖录制时的固定像素。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + let row = 1; + while (row < table.rowCount && table.getCellValue(0, row) !== 'Lazy group') row++; + if (row === table.rowCount) throw new Error('懒加载节点缺失'); + const bounds = table.getCellRect(0, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + bounds.x1 + 22, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 异步式子节点注入必须改变源记录和可见表体。 + await page.waitForFunction(() => Array.isArray(window.__visualTable.records[1].children)); + await page.evaluate(() => { + const table = window.__visualTable; + const values = Array.from({ length: table.rowCount - 1 }, (_, index) => table.getCellValue(0, index + 1)); + if (!values.includes('Lazy child A') || !values.includes('Lazy child B')) + throw new Error(`懒加载子节点未显示:${values.join(', ')}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/list-merge-expand.mjs b/packages/vtable/__tests__/visual/cases/tree/list-merge-expand.mjs new file mode 100644 index 0000000000..19ef38b28c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/list-merge-expand.mjs @@ -0,0 +1,33 @@ +/** + * BugServer case IDs: 6613d5fb2acd9c00d1c98a3f + * 验证目的:树形列表中相邻值合并后,点击层级图标仍能展开子行。 + * 改写:层级标识和日期列替换为通用分组;保留树、合并列与录制点击。 + */ +export default { + mount(container) { + // 两个父节点各有子行,合并列的数据保持相邻重复。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'item', title: 'Item', width: 260, tree: true }, + { field: 'value', title: 'Value', width: 180, mergeCell: true }], + records: [{ item: 'Group A', value: 1, children: [{ item: 'A1', value: 1 }] }, + { item: 'Group B', value: 2, children: [{ item: 'B1', value: 2 }] }], + frozenColCount: 1, defaultRowHeight: 30, heightMode: 'autoHeight', autoWrapText: true + }); + }, + async exercise(page) { + // 点击首行左侧的层级图标,复现来源录制的展开动作。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(0, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x1 + 22, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 首个节点应变成展开状态,子行应加入可见行。 + await page.waitForFunction(() => window.__visualTable.getHierarchyState(0, 1) === 'expand'); + await page.evaluate(() => { + if (window.__visualTable.rowCount < 4) throw new Error('树形子行未展开'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/pagination-double-click.mjs b/packages/vtable/__tests__/visual/cases/tree/pagination-double-click.mjs new file mode 100644 index 0000000000..ad8ddba63b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/pagination-double-click.mjs @@ -0,0 +1,57 @@ +/** + * BugServer case IDs: 67371af030877400b3e630f6 + * 验证目的:树形列表在分页第二页双击表体单元格时,事件仍对应当前可见记录。 + * 改写:商品层级与数字替换为通用分组,保留分页、树节点与录制的双击动作。 + */ +export default { + mount(container) { + // 每页两条根记录,第二页包含普通树和懒加载占位节点。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Group', tree: true, width: 200, sort: true }, + { field: 'value', title: 'Value', width: 120, sort: true }], + records: [ + { name: 'Group A', value: 10, children: [{ name: 'A1', value: 10 }] }, + { name: 'Group B', value: 20, children: [{ name: 'B1', value: 20 }] }, + { name: 'Group C', value: 30, children: [{ name: 'C1', value: 30 }] }, + { name: 'Lazy group', value: 40, children: true } + ], + pagination: { perPageCount: 2, currentPage: 1 }, + hierarchyIndent: 20, hierarchyExpandLevel: 2, + showPin: true, allowFrozenColCount: 2, theme: window.VTable.themes.BRIGHT, + defaultRowHeight: 32 + }); + window.__treePageDoubleClicks = []; + table.on(window.VTable.ListTable.EVENT_TYPE.DBLCLICK_CELL, event => { + // 记录双击事件的行列位置与可见值,确认没有映射到第一页。 + window.__treePageDoubleClicks.push({ col: event.col, row: event.row, + value: table.getCellValue(event.col, event.row) }); + }); + table.on(window.VTable.ListTable.EVENT_TYPE.TREE_HIERARCHY_STATE_CHANGE, args => { + // 来源允许对分页中的懒加载占位行动态补充子记录。 + if (args.hierarchyState === window.VTable.TYPES.HierarchyState.expand && + !Array.isArray(args.originData.children)) + table.setRecordChildren([{ name: 'Lazy child', value: 40 }], args.col, args.row); + }); + return table; + }, + async exercise(page) { + // 双击第二页首条记录的数据列,重放来源中的连续点击。 + const point = await page.evaluate(() => { + const bounds = window.__visualTable.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (bounds.x1 + bounds.x2) / 2, + y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.dblclick(point.x, point.y, { delay: 80 }); + await page.waitForFunction(() => window.__treePageDoubleClicks.length > 0); + }, + async verify(page) { + // 事件值必须来自第二页当前可见的记录,并且树结构仍在。 + await page.evaluate(() => { + const table = window.__visualTable; + const event = window.__treePageDoubleClicks[0]; + if (!event || event.value !== 30 || table.getCellValue(0, 1) !== 'Group C') + throw new Error(`树分页双击映射错误:${JSON.stringify(event)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/tree/zero-height-toggle.mjs b/packages/vtable/__tests__/visual/cases/tree/zero-height-toggle.mjs new file mode 100644 index 0000000000..5ca7532d78 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/tree/zero-height-toggle.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 6a69af4d02c575005f77ab2c + * 验证目的:过滤后高度为零的树子行在折叠与展开后不阻止可见行填满视口。 + * 改写:来源的 300 个隐藏行及 40 个可见行缩为固定匿名分组。 + */ +export default { + mount(container) { + // 第一组可在过滤后隐藏子行,第二组保留足够多的可见行填满视口。 + container.style.width = '720px'; + container.style.height = '360px'; + const hiddenChildren = Array.from({ length: 24 }, (_, index) => ({ + name: `Hidden ${index + 1}`, visible: true + })); + const records = [ + { name: 'Filtered group', visible: true, hierarchyState: 'expand', children: hiddenChildren }, + { name: 'Visible group', visible: true, hierarchyState: 'expand', + children: Array.from({ length: 12 }, (_, index) => ({ name: `Visible ${index + 1}`, visible: true })) } + ]; + const options = { + columns: [{ field: 'name', title: 'Name', tree: true, width: 260 }], + records, defaultRowHeight: 40, hierarchyExpandLevel: 2, + customComputeRowHeight({ row, table }) { + // 已过滤的原始记录占零高度,其他树行维持固定高度。 + return table.getCellOriginRecord(0, row)?.visible === false ? 0 : 40; + } + }; + const table = new window.VTable.ListTable(container, options); + return { + table, hiddenChildren, options, + async renderAsync() { + // 等待树形表初始绘制。 + await table.renderAsync?.(); + }, + release() { + // 清理树形表实例。 + table.release(); + } + }; + }, + async exercise(page) { + // 标记子记录不可见、清空行高缓存并重复折叠展开首个分组。 + await page.evaluate(async () => { + const fixture = window.__visualTable; + fixture.hiddenChildren.forEach(child => { child.visible = false; }); + await fixture.table.updateOption(fixture.options, { clearRowHeightCache: true, clearColWidthCache: false }); + fixture.table.toggleHierarchyState(0, 1, false); + fixture.table.toggleHierarchyState(0, 1, false); + }); + }, + async verify(page) { + // 第一隐藏行仍为零高,场景图已把后续可见行拉进可视区域。 + await page.evaluate(() => { + const table = window.__visualTable.table; + const bodyHeight = table.tableNoFrameHeight - table.getFrozenRowsHeight() - table.getBottomFrozenRowsHeight(); + const renderedHeight = table.getRowsHeight(table.frozenRowCount, table.scenegraph.proxy.rowEnd); + const hiddenHeight = table.getRowHeight(table.columnHeaderLevelCount + 1); + if (hiddenHeight !== 0 || renderedHeight < bodyHeight) + throw new Error(`零高度树行未正确处理:${JSON.stringify({ hiddenHeight, renderedHeight, bodyHeight })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/page.html b/packages/vtable/__tests__/visual/page.html new file mode 100644 index 0000000000..c8ea975069 --- /dev/null +++ b/packages/vtable/__tests__/visual/page.html @@ -0,0 +1,53 @@ + + + + + + + VTable visual regression + + + +
+ + + diff --git a/packages/vtable/__tests__/visual/playwright.config.mjs b/packages/vtable/__tests__/visual/playwright.config.mjs new file mode 100644 index 0000000000..17caa4b118 --- /dev/null +++ b/packages/vtable/__tests__/visual/playwright.config.mjs @@ -0,0 +1,37 @@ +import path from 'node:path'; +import { defineConfig } from '@playwright/test'; +import { settings } from './settings.mjs'; + +const runDir = process.env.VISUAL_RUN_DIR; +const phase = process.env.VISUAL_PHASE; +if (!runDir || !['baseline', 'current'].includes(phase)) throw new Error('请通过 visual-test.mjs 运行'); + +export default defineConfig({ + testDir: '.', + testMatch: 'visual.spec.mjs', + workers: 1, + retries: 0, + timeout: settings.timeout, + outputDir: path.join(runDir, `${phase}-results`), + snapshotPathTemplate: path.join(runDir, 'snapshots', '{arg}{ext}'), + updateSnapshots: phase === 'baseline' ? 'all' : 'none', + expect: { timeout: 5000, toMatchSnapshot: settings.comparison }, + reporter: [ + ['line'], + ['html', { outputFolder: path.join(runDir, `${phase}-report`), open: 'never' }], + ['json', { outputFile: path.join(runDir, `${phase}-playwright.json`) }], + ['./reporter.mjs'] + ], + use: { + browserName: 'chromium', + headless: true, + viewport: settings.viewport, + deviceScaleFactor: settings.deviceScaleFactor, + locale: settings.locale, + timezoneId: settings.timezoneId, + colorScheme: 'light', + reducedMotion: 'reduce', + serviceWorkers: 'block', + trace: 'retain-on-failure' + } +}); diff --git a/packages/vtable/__tests__/visual/report.mjs b/packages/vtable/__tests__/visual/report.mjs new file mode 100644 index 0000000000..b485945b20 --- /dev/null +++ b/packages/vtable/__tests__/visual/report.mjs @@ -0,0 +1,442 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; + +/** 转义报告中的动态文本,同时用于 HTML 内容和属性。 */ +function escape(value) { + return String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +/** 复现参数以单引号包裹,避免目录或报告文字被 shell 解释。 */ +function quote(value) { + return `'${String(value).replaceAll("'", "'\\''")}'`; +} + +/** 人与 Agent 共用范围说明;未选用例不被描述为已通过。 */ +function selectionDescription(report) { + const selection = report.selection; + if (!selection) return `范围未记录;本次记录 ${report.cases.length} 个用例`; + const label = + selection.mode === 'all' + ? '全部本地用例' + : `${selection.mode === 'directory' ? '目录' : '单用例'} ${selection.value}`; + return `${label};选中 ${selection.selectedCount} / ${selection.totalCount};其余 ${ + selection.totalCount - selection.selectedCount + } 个未执行`; +} + +/** 将已存在的运行内文件转换为可搬迁的相对路径,拒绝越界引用。 */ +async function artifact(runDir, relative) { + if (!relative || path.isAbsolute(relative) || relative.split(/[\\/]/).includes('..')) return null; + try { + return (await fs.stat(path.join(runDir, relative))).isFile() ? relative : null; + } catch (error) { + if (error.code === 'ENOENT') return null; + throw error; + } +} + +/** 汇合两阶段结果;缺少图片或未完成比较不能被解释为通过。 */ +export async function saveReport(runDir, summary) { + const phases = {}; + const reportStarted = performance.now(); + const issues = [...(summary.issues ?? [])]; + const selection = summary.selection; + if ( + selection && + (!['all', 'directory', 'case'].includes(selection.mode) || + !Number.isSafeInteger(selection.totalCount) || + selection.totalCount < summary.cases.length || + selection.selectedCount !== summary.cases.length || + !Array.isArray(selection.selectedIds) || + selection.selectedIds.length !== summary.cases.length || + new Set(selection.selectedIds).size !== summary.cases.length || + summary.cases.some(item => !selection.selectedIds.includes(item.id)) || + (selection.mode === 'all' && (selection.value !== null || selection.totalCount !== selection.selectedCount)) || + (selection.mode !== 'all' && typeof selection.value !== 'string') || + (selection.mode === 'case' && (selection.selectedCount !== 1 || selection.selectedIds[0] !== selection.value))) + ) + issues.push({ + phase: 'report', + category: 'execution', + code: 'RESULT_SET_MISMATCH', + message: '报告范围与选中用例集合不一致' + }); + for (const phase of ['baseline', 'current']) { + phases[phase] = summary[`${phase}Result`]; + if (!phases[phase]) { + try { + phases[phase] = JSON.parse(await fs.readFile(path.join(runDir, `${phase}-result.json`), 'utf8')); + } catch (error) { + if (error.code !== 'ENOENT') + issues.push({ phase, category: 'report', code: 'REPORT_FAILED', message: String(error) }); + } + } + for (const message of phases[phase]?.errors ?? []) + issues.push({ phase, category: 'execution', code: 'EXECUTION_FAILED', message }); + } + if (summary.error) + issues.push({ phase: summary.stage ?? 'preparation', category: 'execution', message: summary.error }); + if (summary.cleanupError) issues.push({ phase: 'cleanup', category: 'execution', message: summary.cleanupError }); + for (const [phase, result] of Object.entries(phases)) { + if (!result) continue; + const expected = summary.cases.map(item => item.id); + const actual = result.tests.map(item => item.id); + if ( + actual.length !== expected.length || + new Set(actual).size !== actual.length || + actual.some(id => !expected.includes(id)) + ) + issues.push({ phase, category: 'execution', code: 'RESULT_SET_MISMATCH', message: '阶段结果与选择集不一致' }); + if (result.finalized === false) + issues.push({ phase, category: 'execution', code: 'RUN_INCOMPLETE', message: '阶段异常结束,保留已完成用例' }); + } + // 预检失败时尚未解析基线,复现仍应保留用户请求的 SHA 或自比较模式。 + const baselineSha = summary.baseline?.sha ?? summary.request?.baseline; + const baselineArg = + summary.baseline?.repository === 'working-tree' || summary.request?.['self-compare'] + ? '--self-compare' + : baselineSha + ? `--baseline ${baselineSha}` + : ''; + const cases = []; + for (const item of summary.cases) { + const baseline = phases.baseline?.tests.find(test => test.id === item.id); + const current = phases.current?.tests.find(test => test.id === item.id); + const errors = []; + const images = { baseline: null, current: null, diff: null }; + for (const [phase, result] of [ + ['baseline', baseline], + ['current', current] + ]) { + for (const message of result?.errors ?? []) { + errors.push({ + phase, + stage: result.stage ?? 'execution', + category: result.status === 'diff' ? 'visual_difference' : result.category ?? 'execution', + code: result.code ?? (result.status === 'diff' ? 'VISUAL_DIFFERENCE' : 'EXECUTION_FAILED'), + message + }); + } + images[phase] = await artifact(runDir, result?.attachments?.find(file => file.name === 'rendered')?.path); + if (['passed', 'diff'].includes(result?.status) && !images[phase]) { + errors.push({ + phase, + stage: 'report', + category: 'missing_artifact', + code: 'MISSING_ARTIFACT', + message: '缺少最终截图' + }); + } + } + images.diff = await artifact(runDir, current?.attachments?.find(file => file.name.endsWith('-diff.png'))?.path); + if (current?.status === 'diff' && !images.diff) + errors.push({ + phase: 'current', + stage: 'report', + category: 'missing_artifact', + code: 'MISSING_ARTIFACT', + message: '缺少差异图' + }); + const executionError = + errors.some(error => error.category !== 'visual_difference') || + [baseline, current].some(result => result?.status === 'error'); + const status = executionError + ? 'error' + : baseline?.status !== 'passed' || !current || current.status === 'not_run' + ? 'not_run' + : current.status; + const attachments = []; + for (const [phase, result] of [ + ['baseline', baseline], + ['current', current] + ]) { + for (const file of result?.attachments ?? []) { + const relative = await artifact(runDir, file.path); + if (relative) attachments.push({ phase, ...file, path: relative }); + } + } + cases.push({ + ...item, + status, + ...(status === 'not_run' + ? { + blockedBy: { + phase: baseline?.status === 'passed' ? 'current' : 'baseline', + reason: '前序阶段失败或该阶段未完成' + } + } + : {}), + phases: { baseline: baseline?.status ?? 'not_run', current: current?.status ?? 'not_run' }, + durationMs: (baseline?.durationMs ?? 0) + (current?.durationMs ?? 0), + images, + attachments, + errors, + rerun: `node packages/vtable/scripts/visual-test.mjs ${baselineArg} --case ${quote(item.id)}`.replace(' ', ' ') + }); + } + const counts = Object.fromEntries( + ['passed', 'diff', 'error', 'not_run'].map(status => [status, cases.filter(item => item.status === status).length]) + ); + const complete = + cases.length > 0 && + cases.every(item => ['passed', 'diff'].includes(item.status)) && + !issues.some(issue => ['RESULT_SET_MISMATCH', 'RUN_INCOMPLETE'].includes(issue.code)); + const status = summary.status === 'error' || issues.length || !complete ? 'error' : counts.diff ? 'diff' : 'passed'; + const logs = {}; + for (const name of [ + 'build.log', + 'baseline.log', + 'current.log', + 'baseline-report/index.html', + 'current-report/index.html' + ]) { + const relative = await artifact(runDir, name); + if (relative) logs[name] = relative; + } + const { baselineResult, currentResult, ...metadata } = summary; + const report = { + ...metadata, + schemaVersion: 1, + finalized: summary.finalized ?? true, + status, + complete, + counts, + cases, + issues, + logs, + rerun: selection + ? [ + 'node packages/vtable/scripts/visual-test.mjs', + baselineArg, + selection.mode === 'all' + ? '' + : `${selection.mode === 'directory' ? '--dir' : '--case'} ${quote(selection.value)}` + ] + .filter(Boolean) + .join(' ') + : null, + environment: { + ...summary.environment, + browser: phases.current?.browser ?? phases.baseline?.browser ?? summary.environment.browser + } + }; + // 汇总只生成新对象;HTML 和 Markdown 不改变调用方的状态。 + report.timings = { ...summary.timings, reportMs: Math.round(performance.now() - reportStarted) }; + await writeJson(path.join(runDir, 'summary.json'), report); + await fs.writeFile(path.join(runDir, 'agent-summary.md'), agentSummary(report)); + await fs.writeFile(path.join(runDir, 'index.html'), renderHtml(report)); + report.timings.reportMs = Math.round(performance.now() - reportStarted); + if (report.timings.totalMs !== undefined) report.timings.totalMs += report.timings.reportMs; + await writeJson(path.join(runDir, 'summary.json'), report); + await fs.writeFile(path.join(runDir, 'agent-summary.md'), agentSummary(report)); + await fs.writeFile(path.join(runDir, 'index.html'), renderHtml(report)); + return report; +} + +/** 输出失败优先的纯文本入口,让 Agent 按路径读取证据而非消耗 Base64。 */ +function agentSummary(report) { + const lines = [ + '# VTable 视觉回归结果', + '', + `状态:${report.status};完整比较:${report.complete};${JSON.stringify(report.counts)}`, + `测试范围:${selectionDescription(report)}`, + ...(report.rerun ? [`本次范围复现:\`${report.rerun}\``] : []), + '', + `基线:${report.baseline?.repository ?? '未解析'} @ ${report.baseline?.sha ?? '未解析'}`, + `本地:${report.local?.head ?? '未知'};dirty=${report.local?.dirty ?? '未知'};工作区摘要=${ + report.local?.digest ?? '未知' + }`, + `环境:${JSON.stringify(report.environment)}`, + '', + '完整结构化结果:[summary.json](summary.json)(schemaVersion=1);所有证据路径相对于此报告目录。', + '以下记录测试事实,不判断差异是否属于缺陷。复现命令在仓库根目录执行;基线 SHA 固定,本地工作区需要与摘要一致。', + '用例 source.path 指向仓库文件;source.frozenPath 指向本次运行冻结文件。', + '截图需由支持图片的 Agent 按需打开;本报告不调用模型,也不自动接受差异。', + '' + ]; + for (const issue of report.issues) + lines.push( + `## 运行错误:${issue.phase} / ${issue.code ?? issue.category}`, + '', + ...issue.message.split('\n').map(line => `> ${line}`), + '' + ); + for (const item of report.cases.filter(item => item.status !== 'passed')) { + lines.push( + `## ${item.id} — ${item.status}`, + '', + item.purpose, + '', + `源码:${item.source?.path ?? '未知'}:${item.source?.line ?? '?'};冻结副本:${ + item.source?.frozenPath ?? '未知' + }`, + `阶段:${JSON.stringify(item.phases)}`, + '', + `复现:\`${item.rerun}\``, + '' + ); + for (const [kind, file] of Object.entries(item.images)) + lines.push(`- ${kind}:${file ? `[${file}](${file})` : '未生成或缺失'}`); + for (const error of item.errors) + lines.push( + '', + `${error.phase} / ${error.stage} / ${error.code ?? error.category}`, + ...error.message.split('\n').map(line => `> ${line}`) + ); + lines.push(''); + } + if (report.complete && !report.counts.diff) lines.push('所选用例全部通过,详情见 summary.json。', ''); + lines.push('## 日志与详细报告', '', ...Object.values(report.logs).map(file => `- [${file}](${file})`), ''); + return lines.join('\n'); +} + +/** 生成无需服务和网络的三图报告;原图链接保留完整分辨率。 */ +function renderHtml(report) { + const labels = { passed: '通过', diff: '视觉差异', error: '执行错误', not_run: '未完成' }; + const link = (file, label) => `${escape(label)}`; + const baseline = report.baseline?.repository === 'working-tree' ? '工作区自比较' : '官方基线'; + const cards = report.cases + .map( + item => `
+

${escape(item.id)}

${ + labels[item.status] + }${(item.durationMs / 1000).toFixed(1)}s
+

${escape(item.purpose)}

${[ + ['baseline', `${baseline} · ${report.baseline?.sha?.slice(0, 8) ?? '?'}`], + ['current', `本地 · ${report.local?.head?.slice(0, 8) ?? '?'}${report.local?.dirty ? ' + 未提交修改' : ''}`], + ['diff', 'Diff · 差异图'] + ] + .map( + ([kind, title]) => + `
${escape(title)}
${ + item.images[kind] + ? `${escape(`${item.id} ${title}`)}` + : `
${ + kind === 'diff' && item.status === 'passed' ? '无视觉差异' : '未生成或缺失;请查看状态与诊断' + }
` + }
` + ) + .join('')}
+

用例:${escape(item.source?.path)}:${item.source?.line ?? '?'} · ${ + item.source?.frozenPath ? link(item.source.frozenPath, '查看冻结用例') : '' + } · baseline=${item.phases.baseline} / current=${item.phases.current}

+
${escape(item.rerun)}
+ ${ + item.errors.length + ? `
诊断(${ + item.errors.length + })${item.errors + .map( + error => + `

${escape(`${error.phase} / ${error.stage} / ${error.code ?? error.category}`)}

${escape(
+                  error.message
+                )}
` + ) + .join('')}
` + : '' + } + ${ + item.attachments.length + ? `
证据文件
    ${item.attachments + .map(file => `
  • ${escape(file.phase)} · ${link(file.path, file.name)}
  • `) + .join('')}
` + : '' + }
` + ) + .join(''); + return `VTable 视觉回归 · ${ + labels[report.status] + } +

VTable 视觉回归 · ${labels[report.status]}

${escape(report.startedAt)} · ${ + report.complete ? '所选用例完成比较' : '比较未完整完成' + } · ${escape(report.environment.platform)} / ${escape(report.environment.arch)} · Chromium ${escape( + report.environment.browser ?? '未启动' + )}

基线 ${escape(report.baseline?.sha ?? '未解析')} · 本地 ${escape(report.local?.head ?? '未解析')}${ + report.local?.dirty ? '(有未提交修改)' : '' + }

${escape(selectionDescription(report))}

+
${Object.entries(report.counts) + .map(([status, count]) => `
${count}${labels[status]}
`) + .join('')}
+

同机、同一套用例对比。点击图片打开原图;视觉差异需要审查,不自动判为缺陷。

+ ${ + report.rerun + ? `

本次范围复现:

${escape( + report.rerun + )}
` + : '' + } + ${report.issues + .map( + issue => + `
${escape( + `${issue.phase} / ${issue.code ?? issue.category}` + )}
${escape(issue.message)}
` + ) + .join('')} +
${cards} +
+ `; +} + +/** 在报告目录内原子替换 JSON,避免读者看到半写入的终态。 */ +async function writeJson(file, value) { + const temporary = `${file}.tmp`; + await fs.writeFile(temporary, JSON.stringify(value, null, 2)); + await fs.rename(temporary, file); +} diff --git a/packages/vtable/__tests__/visual/reporter.mjs b/packages/vtable/__tests__/visual/reporter.mjs new file mode 100644 index 0000000000..153dfc10bd --- /dev/null +++ b/packages/vtable/__tests__/visual/reporter.mjs @@ -0,0 +1,90 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { stripVTControlCharacters } from 'node:util'; + +/** 每个完成用例即保存证据,不依赖进程正常结束才落盘。 */ +export default class VisualReporter { + tests = []; + errors = []; + onError(error) { + // 记录 worker 等运行级错误,并保留已完成用例。 + this.errors.push(stripVTControlCharacters(error.message ?? String(error))); + this.persist(false); + } + onTestEnd(test, result) { + // diff 标记仅由截图适配层在确认原生比较证据完整后添加。 + const difference = result.attachments.some(item => item.name === 'visual-difference'); + const stage = test.annotations.find(item => item.type === 'stage')?.description ?? 'setup'; + const category = + result.status === 'timedOut' + ? 'timeout' + : test.annotations.find(item => item.type === 'failure-category')?.description || stage; + const codes = { + resource: 'RESOURCE_FAILED', + render: 'RENDER_FAILED', + interaction: 'INTERACTION_ASSERTION_FAILED', + verify: 'CASE_ASSERTION_FAILED', + screenshot: 'SCREENSHOT_FAILED', + comparison: 'COMPARISON_FAILED', + timeout: 'TIMEOUT', + missing_artifact: 'MISSING_ARTIFACT', + setup: 'PREFLIGHT_FAILED' + }; + this.browser = test.annotations.find(item => item.type === 'browser')?.description ?? this.browser; + this.tests.push({ + id: test.title, + status: + result.status === 'passed' + ? 'passed' + : result.status === 'skipped' + ? 'not_run' + : result.status === 'failed' && difference + ? 'diff' + : 'error', + stage, + category, + code: + result.status === 'passed' + ? null + : result.status === 'skipped' + ? 'RUN_INCOMPLETE' + : difference + ? 'VISUAL_DIFFERENCE' + : codes[category] ?? 'EXECUTION_FAILED', + durationMs: result.duration, + errors: result.errors.map(error => stripVTControlCharacters(error.message ?? String(error))), + attachments: result.attachments + .filter(item => item.path) + .map(item => ({ + name: item.name, + contentType: item.contentType, + path: path.relative(process.env.VISUAL_RUN_DIR, item.path).split(path.sep).join('/') + })) + }); + this.persist(false); + } + persist(finalized, endedStatus) { + // 原子替换阶段结果;未终结的阶段始终不宣称完整成功。 + const status = + !finalized || + this.errors.length || + !this.tests.length || + this.tests.some(test => ['error', 'not_run'].includes(test.status)) || + ['interrupted', 'timedout'].includes(endedStatus) + ? 'error' + : this.tests.some(test => test.status === 'diff') + ? 'diff' + : 'passed'; + const file = path.join(process.env.VISUAL_RUN_DIR, `${process.env.VISUAL_PHASE}-result.json`); + const temporary = `${file}.tmp`; + fs.writeFileSync( + temporary, + JSON.stringify({ finalized, status, browser: this.browser, tests: this.tests, errors: this.errors }, null, 2) + ); + fs.renameSync(temporary, file); + } + onEnd(result) { + // 最终更新状态,保留每个用例独立写入的原始诊断。 + this.persist(true, result.status); + } +} diff --git a/packages/vtable/__tests__/visual/settings.mjs b/packages/vtable/__tests__/visual/settings.mjs new file mode 100644 index 0000000000..57ca4183b4 --- /dev/null +++ b/packages/vtable/__tests__/visual/settings.mjs @@ -0,0 +1,12 @@ +/** 两阶段共用的确定性环境与像素比较策略。 */ +export const settings = { + viewport: { width: 1000, height: 800 }, + table: { width: 800, height: 600 }, + deviceScaleFactor: 1, + locale: 'en-US', + timezoneId: 'UTC', + fontFamily: 'Arial', + timeout: 30000, + stableTimeout: 5000, + comparison: { threshold: 0.1, maxDiffPixels: 0 } +}; diff --git a/packages/vtable/__tests__/visual/visual.spec.mjs b/packages/vtable/__tests__/visual/visual.spec.mjs new file mode 100644 index 0000000000..9517da521e --- /dev/null +++ b/packages/vtable/__tests__/visual/visual.spec.mjs @@ -0,0 +1,135 @@ +import fs from 'node:fs/promises'; +import { test, expect } from '@playwright/test'; +import { cases, loadCase } from './cases/index.mjs'; +import { settings } from './settings.mjs'; + +/** 等待两张连续截图完全一致;持续变化视为执行错误而非像素差异。 */ +async function stableScreenshot(page) { + let previous; + const deadline = Date.now() + settings.stableTimeout; + while (Date.now() < deadline) { + const current = await page.screenshot({ animations: 'disabled', timeout: 5000 }); + if (previous?.equals(current)) return current; + previous = current; + await page.waitForTimeout(100); + } + throw new Error('截图持续变化,5 秒内未稳定'); +} + +/** 检查表格确实生成了可见画布与非空像素,避免两侧同为空白时误通过。 */ +async function checkDrawing(page, errors) { + if (errors.length) throw new Error(errors.join('\n')); + await page.evaluate(() => { + if (window.__visualErrors.length) throw new Error(window.__visualErrors.join('\n')); + const container = document.getElementById('table'); + const canvases = [...container.querySelectorAll('canvas')].filter(canvas => canvas.width > 0 && canvas.height > 0); + if (!canvases.length) throw new Error('没有有效表格画布'); + let ink = 0; + for (const canvas of canvases) { + const context = canvas.getContext('2d'); + if (!context) continue; + const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data; + for (let i = 0; i < pixels.length; i += 4) + if (pixels[i + 3] && (pixels[i] < 245 || pixels[i + 1] < 245 || pixels[i + 2] < 245)) ink++; + } + if (ink < 100) throw new Error('表格没有有效绘制'); + }); +} + +const selectedIds = JSON.parse(process.env.VISUAL_CASE_IDS); +for (const metadata of cases.filter(item => selectedIds.includes(item.id))) { + const item = { ...metadata, ...(await loadCase(metadata)) }; + test(item.id, async ({ page, browser }, info) => { + // 记录来源和浏览器版本,并收集整个用例生命周期内的异常。 + info.annotations.push( + { type: 'purpose', description: item.purpose }, + { type: 'browser', description: browser.version() } + ); + const stage = { type: 'stage', description: 'resource' }; + info.annotations.push(stage); + const failure = { type: 'failure-category', description: '' }; + info.annotations.push(failure); + const errors = []; + const base = process.env.VISUAL_BASE_URL; + page.on('pageerror', error => { + failure.description = 'render'; + errors.push(error.message); + }); + page.on('requestfailed', request => { + failure.description = 'resource'; + errors.push(`资源失败:${request.url()} ${request.failure()?.errorText}`); + }); + page.on('response', response => { + if (response.status() >= 400) { + failure.description = 'resource'; + errors.push(`HTTP ${response.status()}:${response.url()}`); + } + }); + await page.route('**/*', route => { + // 截图阶段禁止 CDN 和内网请求。 + if (new URL(route.request().url()).origin === base) return route.continue(); + failure.description = 'resource'; + errors.push(`禁止外部请求:${route.request().url()}`); + return route.abort(); + }); + try { + await page.goto(`${base}/suite/page.html?phase=${process.env.VISUAL_PHASE}&case=${item.id}`); + stage.description = 'render'; + await page.waitForFunction(() => window.__visualReady || window.__visualErrors?.length); + await checkDrawing(page, errors); + stage.description = 'interaction'; + await item.exercise?.(page); + stage.description = item.exercise ? 'interaction' : 'verify'; + await item.verify(page); + stage.description = 'screenshot'; + await page.evaluate(() => document.fonts.ready); + const screenshot = await stableScreenshot(page); + await checkDrawing(page, errors); + const renderedPath = info.outputPath('rendered.png'); + await fs.writeFile(renderedPath, screenshot); + await info.attach('rendered', { path: renderedPath, contentType: 'image/png' }); + stage.description = 'comparison'; + const name = `${item.id}.png`; + if (process.env.VISUAL_PHASE === 'current') { + // 缺失基线必须在图片断言之前归类为执行错误。 + try { + await fs.access(info.snapshotPath(name)); + } catch (error) { + failure.description = 'missing_artifact'; + throw error; + } + } + try { + expect(screenshot).toMatchSnapshot(name); + } catch (error) { + if (process.env.VISUAL_PHASE === 'current' && (await hasComparisonEvidence(info, name))) + await info.attach('visual-difference', { + body: Buffer.from('图像存在差异,请检查是否符合预期'), + contentType: 'text/plain' + }); + throw error; + } + } finally { + // 显式释放图表,浏览器 context 由 Playwright fixture 自动回收。 + await page.evaluate(() => window.__visualTable?.release?.()).catch(() => {}); + } + }); +} + +/** 只有原生比较生成完整 PNG 证据时才允许把断言失败归类为视觉差异。 */ +async function hasComparisonEvidence(info, name) { + const stem = name.slice(0, -4); + const dimensions = []; + for (const kind of ['expected', 'actual', 'diff']) { + const file = info.attachments.find(item => item.name === `${stem}-${kind}.png`)?.path; + if (!file) return false; + try { + const bytes = await fs.readFile(file); + if (bytes.length < 24 || bytes.subarray(0, 8).toString('hex') !== '89504e470d0a1a0a') return false; + dimensions.push(`${bytes.readUInt32BE(16)}x${bytes.readUInt32BE(20)}`); + } catch { + return false; + } + } + return new Set(dimensions).size === 1; +} diff --git a/packages/vtable/package.json b/packages/vtable/package.json index 1d94e3775a..bc109d8f59 100644 --- a/packages/vtable/package.json +++ b/packages/vtable/package.json @@ -47,6 +47,7 @@ "start": "vite serve examples", "test": "jest --silent", "test:firefox": "playwright test --config playwright.config.ts", + "test:visual": "node scripts/visual-test.mjs", "test-cov": "jest --coverage", "ci": "ts-node --transpileOnly --skipProject ./scripts/trigger-test.ts", "build:es": "bundle --clean -f es --ignorePostTasks", diff --git a/packages/vtable/scripts/visual-test.mjs b/packages/vtable/scripts/visual-test.mjs new file mode 100644 index 0000000000..dce81a59d8 --- /dev/null +++ b/packages/vtable/scripts/visual-test.mjs @@ -0,0 +1,86 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseArgs } from 'node:util'; +import { createRuntime, fault } from './visual/runtime.mjs'; +import { loadCases, preflight, runVisual } from './visual/runner.mjs'; + +/** 解析公共命令;帮助不加载 Playwright,非法选项仍明确报错。 */ +export function parseOptions(args) { + let values, tokens; + try { + ({ values, tokens } = parseArgs({ + args, + tokens: true, + options: { + baseline: { type: 'string' }, + case: { type: 'string' }, + dir: { type: 'string' }, + 'self-compare': { type: 'boolean' }, + list: { type: 'boolean' }, + check: { type: 'boolean' }, + help: { type: 'boolean' } + } + })); + } catch (error) { + throw fault('INVALID_ARGUMENT', error.message, error); + } + if (values.help) return values; + if (tokens.filter(token => token.kind === 'option' && token.name === 'dir').length > 1) + throw fault('INVALID_ARGUMENT', '--dir 只能指定一次'); + if (values.dir !== undefined && !/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/.test(values.dir)) + throw fault('INVALID_ARGUMENT', '--dir 需要 cases 内的相对目录,例如 table/cells'); + if (values.dir !== undefined && values.case !== undefined) throw fault('INVALID_ARGUMENT', '--dir 与 --case 互斥'); + if ( + (values.list || values.check) && + ((values.list && values.check) || + values.baseline !== undefined || + values.case !== undefined || + values.dir !== undefined || + values['self-compare']) + ) + throw fault('INVALID_ARGUMENT', '--list/--check 必须独立使用'); + if (values.baseline !== undefined && !/^[a-f0-9]{40}$/i.test(values.baseline)) + throw fault('INVALID_ARGUMENT', '--baseline 需要完整 40 位 SHA'); + if (values.baseline && values['self-compare']) throw fault('INVALID_ARGUMENT', '--baseline 与 --self-compare 互斥'); + if (values.case !== undefined && !/^[a-z][a-z0-9-]*$/.test(values.case)) + throw fault('INVALID_ARGUMENT', '--case 需要有效用例 ID'); + return values; +} +/** 入口只管理参数、预检模式和运行生命周期。 */ +async function main() { + const options = parseOptions(process.argv.slice(2)); + const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); + if (options.help) { + console.log( + 'node packages/vtable/scripts/visual-test.mjs [--baseline <40位SHA> | --self-compare] [--dir <目录> | --case ]\n默认运行全部本地用例;--dir 递归运行 cases 内的一个目录(例如 table/cells)。\n--list 列举用例;--check 本机环境检查;--help 帮助\n默认:官方 VisActor/VTable develop。退出码:0 通过,1 视觉差异,2 执行错误。' + ); + return; + } + if (options.list || options.check) { + const cases = await loadCases(path.join(root, 'packages/vtable/__tests__/visual')); + if (options.list) { + console.log( + cases.map(item => `${item.id}\t${item.purpose}\t${item.file}\t${item.sourceExample ?? ''}`).join('\n') + ); + return; + } + await fs.mkdir(path.join(root, '.vtable-visual'), { recursive: true }); + const runtime = createRuntime(); + const detach = runtime.listenSignals(); + try { + console.log(JSON.stringify({ status: 'passed', ...(await preflight(root, runtime)), cases: cases.length })); + } finally { + const errors = await runtime.cleanup(); + detach(); + if (errors.length) throw fault('CLEANUP_FAILED', JSON.stringify(errors)); + } + return; + } + process.exitCode = await runVisual(root, options); +} +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) + main().catch(error => { + console.error(`${error.code ?? 'EXECUTION_FAILED'}: ${error.message}`); + process.exitCode = 2; + }); diff --git a/packages/vtable/scripts/visual-test.test.mjs b/packages/vtable/scripts/visual-test.test.mjs new file mode 100644 index 0000000000..5d81e29be4 --- /dev/null +++ b/packages/vtable/scripts/visual-test.test.mjs @@ -0,0 +1,19 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseOptions } from './visual-test.mjs'; +import { loadCases, selectCases } from './visual/runner.mjs'; + +/** 用最小契约检查拦住无效范围、重复 ID 和缺失来源模块。 */ +test('视觉用例清单与范围选择', async () => { + const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + const cases = await loadCases(path.join(root, '__tests__/visual')); + assert.ok(cases.length >= 2); + assert.equal(new Set(cases.map(item => item.id)).size, cases.length); + assert.ok(selectCases(cases, { dir: 'pivot' }).every(item => item.file.startsWith('./pivot/'))); + assert.deepEqual(selectCases(cases, { case: 'list-basic' }).map(item => item.id), ['list-basic']); + assert.throws(() => parseOptions(['--dir', '../pivot']), /--dir/); + assert.throws(() => parseOptions(['--dir', 'pivot', '--case', 'list-basic']), /互斥/); + assert.throws(() => selectCases(cases, { dir: 'missing' }), /没有匹配用例/); +}); diff --git a/packages/vtable/scripts/visual/build.mjs b/packages/vtable/scripts/visual/build.mjs new file mode 100644 index 0000000000..9919c7c2fb --- /dev/null +++ b/packages/vtable/scripts/visual/build.mjs @@ -0,0 +1,137 @@ +import { execFileSync } from 'node:child_process'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { digest, atomicJson, fault } from './runtime.mjs'; + +export const official = 'https://github.com/VisActor/VTable.git'; +export const bundleFiles = { + vtable: ['packages/vtable', 'dist/vtable.js'], + editors: ['packages/vtable-editors', 'dist/vtable-editors.js'], + gantt: ['packages/vtable-gantt', 'dist/vtable-gantt.js'], + plugins: ['packages/vtable-plugins', 'dist/vtable-plugins.js'], + sheet: ['packages/vtable-sheet', 'dist/vtable-sheet.js'] +}; +const buildEnv = { NODE_ENV: 'production', BUNDLE_ANALYZE: '', NODE_OPTIONS: '--max-old-space-size=10240' }; + +/** 查询指定仓库,不修改分支、索引或远端配置。 */ +export function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }).trim(); +} +/** 记录提交、已跟踪差异和未跟踪文件,构建期变更会使运行失败。 */ +export async function workingTree(root) { + const status = git(root, ['status', '--short']); + const patch = execFileSync('git', ['diff', 'HEAD', '--binary', '--full-index'], { cwd: root, maxBuffer: 64 * 1024 * 1024 }); + const files = execFileSync('git', ['ls-files', '--others', '--exclude-standard', '-z'], { cwd: root, encoding: 'utf8' }) + .split('\0').filter(Boolean).sort(); + const untracked = []; + for (const file of files) { + const full = path.join(root, file); + const stat = await fs.lstat(full); + untracked.push([file, digest(stat.isSymbolicLink() ? await fs.readlink(full) : await fs.readFile(full))]); + } + return { head: git(root, ['rev-parse', 'HEAD']), dirty: Boolean(status), status, digest: digest(Buffer.concat([patch, Buffer.from(JSON.stringify(untracked))])) }; +} +/** 每次从官方仓库解析本轮 develop 或指定提交,不使用 fork 的 origin。 */ +export async function resolveBaseline(root, sha, runtime, log) { + await runtime.run('git', ['fetch', '--no-tags', official, sha || 'refs/heads/develop'], root, log, { code: 'BASELINE_FETCH_FAILED' }); + const resolved = git(root, ['rev-parse', 'FETCH_HEAD^{commit}']); + if (sha && resolved !== sha.toLowerCase()) throw fault('BASELINE_FETCH_FAILED', '基线 SHA 与请求不一致'); + return resolved; +} +/** 构建所选包及其工作区依赖,并仅复制本轮产物到隔离运行目录。 */ +export async function build(root, runDir, phase, names, runtime, log) { + const rushx = path.join(root, 'common/scripts/install-run-rushx.js'); + // Gantt 的 bundler.config 从 bundler 工具包解析 Rollup 插件。 + const env = { ...buildEnv, NODE_PATH: path.join(root, 'tools/bundler/node_modules') }; + await runtime.run(process.execPath, [rushx, 'build'], path.join(root, 'tools/bundler'), log, { code: 'BUILD_FAILED', env }); + const bundle = path.join(root, 'tools/bundler/bin/index.js'); + const need = new Set(names); + const esPackages = ['vtable-editors', 'vtable']; + if (['gantt', 'plugins', 'sheet'].some(name => need.has(name))) esPackages.push('vtable-gantt'); + if (['plugins', 'sheet'].some(name => need.has(name))) esPackages.push('vtable-plugins'); + for (const name of esPackages) + await runtime.run(process.execPath, [bundle, '-f', 'es', '--ignorePostTasks'], path.join(root, 'packages', name), log, { code: 'BUILD_FAILED', env }); + for (const name of names) { + const destination = path.join(runDir, `${phase}-${name}.js`); + if (name === 'vchart') { + const require = (await import('node:module')).createRequire(path.join(root, 'packages/vtable/package.json')); + const packageRoot = path.dirname(require.resolve('@visactor/vchart/package.json')); + const source = path.join(packageRoot, 'build/index.min.js'); + if (!(await fs.stat(source)).size) throw fault('BUILD_FAILED', '缺少 VChart 本地产物'); + await fs.copyFile(source, destination); + continue; + } + const [folder, relative] = bundleFiles[name] ?? []; + if (!folder) throw fault('BUILD_FAILED', `未知构建包:${name}`); + const output = path.join(folder, relative); + if (git(root, ['ls-files', '--', output])) throw fault('BUILD_FAILED', `构建目标被 Git 跟踪:${output}`); + try { git(root, ['check-ignore', '--no-index', output]); } + catch { throw fault('BUILD_FAILED', `构建目标未忽略:${output}`); } + await fs.rm(path.join(root, output), { force: true }); + await runtime.run(process.execPath, [bundle, '-f', 'umd', '--minify=false', '--ignorePostTasks'], path.join(root, folder), log, { code: 'BUILD_FAILED', env }); + if (!(await fs.stat(path.join(root, output))).size) throw fault('BUILD_FAILED', `没有生成有效产物:${output}`); + await fs.copyFile(path.join(root, output), destination); + } +} +/** 逐文件校验缓存摘要;坏缓存只导致重新构建。 */ +async function readCache(cache, key, names) { + try { + const metadata = JSON.parse(await fs.readFile(path.join(cache, 'metadata.json'), 'utf8')); + if (metadata.key !== key) return null; + const files = new Map(); + for (const name of names) { + const bytes = await fs.readFile(path.join(cache, `${name}.js`)); + if (!bytes.length || digest(bytes) !== metadata.files?.[name]) return null; + files.set(name, bytes); + } + return files; + } catch (error) { + if (error.code === 'ENOENT' || error instanceof SyntaxError) return null; + throw error; + } +} +/** 成功构建后原子发布完整缓存,不用半份产物覆盖既有缓存。 */ +async function publishCache(cache, key, files) { + const temporary = await fs.mkdtemp(`${cache}-next-`); + const old = `${cache}-previous`; + try { + const hashes = {}; + for (const [name, bytes] of files) { + await fs.writeFile(path.join(temporary, `${name}.js`), bytes); + hashes[name] = digest(bytes); + } + await atomicJson(path.join(temporary, 'metadata.json'), { key, files: hashes }); + await fs.rm(old, { recursive: true, force: true }); + try { await fs.rename(cache, old); } catch (error) { if (error.code !== 'ENOENT') throw error; } + try { await fs.rename(temporary, cache); } + catch (error) { try { await fs.rename(old, cache); } catch {} throw error; } + await fs.rm(old, { recursive: true, force: true }); + } finally { await fs.rm(temporary, { recursive: true, force: true }); } +} +/** 按 SHA、锁文件、环境、包集合和构建配方缓存最近一次官方产物。 */ +export async function baselineBuild(root, runDir, sha, names, runtime, report, timed) { + const log = path.join(runDir, 'build.log'); + const key = digest(JSON.stringify({ + sha, names, lock: git(root, ['show', `${sha}:common/config/rush/pnpm-lock.yaml`]), + node: process.version, platform: process.platform, arch: process.arch, + recipe: digest(await fs.readFile(fileURLToPath(import.meta.url))), buildEnv, + tools: git(root, ['show', `${sha}:rush.json`]) + })); + const cache = path.join(root, '.vtable-visual/baseline-cache'); + const cached = await readCache(cache, key, names); + if (cached) { + for (const [name, bytes] of cached) await fs.writeFile(path.join(runDir, `baseline-${name}.js`), bytes); + report.baseline.cacheHit = true; + return; + } + const worktree = path.join(runDir, 'worktree'); + runtime.defer(async () => { + if (await fs.stat(worktree).catch(error => error.code === 'ENOENT' ? null : Promise.reject(error))) + execFileSync('git', ['worktree', 'remove', '--force', worktree], { cwd: root, stdio: 'pipe', timeout: 60000 }); + }); + await runtime.run('git', ['worktree', 'add', '--detach', worktree, sha], root, log, { code: 'BUILD_FAILED' }); + await timed('baselineInstallMs', () => runtime.run(process.execPath, ['common/scripts/install-run-rush.js', 'install', '--ignore-hooks'], worktree, log, { code: 'BUILD_FAILED', env: { NODE_ENV: 'development' } })); + await timed('baselineCompileMs', () => build(worktree, runDir, 'baseline', names, runtime, log)); + await publishCache(cache, key, new Map(await Promise.all(names.map(async name => [name, await fs.readFile(path.join(runDir, `baseline-${name}.js`))])))); +} diff --git a/packages/vtable/scripts/visual/runner.mjs b/packages/vtable/scripts/visual/runner.mjs new file mode 100644 index 0000000000..41b3da65bb --- /dev/null +++ b/packages/vtable/scripts/visual/runner.mjs @@ -0,0 +1,350 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { createRequire } from 'node:module'; +import { randomUUID } from 'node:crypto'; +import { createRuntime, serve, fault, digest, atomicJson, fileManifest } from './runtime.mjs'; +import { git, workingTree, resolveBaseline, build, baselineBuild, official } from './build.mjs'; +import { saveReport } from '../../__tests__/visual/report.mjs'; + +/** 验证元数据和可执行契约,只导入实际使用的清单目录。 */ +export async function loadCases(suite, caseId) { + try { + // 列举也检查全部目录,导入前拒绝父目录和辅助资源中的符号链接。 + if ((await fs.lstat(path.join(suite, 'cases'))).isSymbolicLink()) throw new Error('cases 不能为符号链接'); + await fileManifest(path.join(suite, 'cases')); + const { cases, loadCase } = await import(pathToFileURL(path.join(suite, 'cases/index.mjs'))); + if (!Array.isArray(cases) || !cases.length) throw new Error('用例清单为空'); + const ids = new Set(); + for (const item of cases) { + if (!/^[a-z][a-z0-9-]*$/.test(item.id) || ids.has(item.id)) throw new Error(`非法或重复 ID:${item.id}`); + ids.add(item.id); + if ( + !item.purpose || + (item.sourceExample !== undefined && (typeof item.sourceExample !== 'string' || !item.sourceExample.trim())) || + !Array.isArray(item.bundles) || !item.bundles.length || item.bundles.some(name => !['vtable', 'editors', 'gantt', 'plugins', 'sheet', 'vchart'].includes(name)) || new Set(item.bundles).size !== item.bundles.length || + typeof item.file !== 'string' || + !/^\.\/([a-z][a-z0-9-]*\/)*[a-z][a-z0-9-]*\.mjs$/.test(item.file) + ) + throw new Error(`非法用例元数据:${item.id}`); + const file = path.join(suite, 'cases', item.file); + if ((await fs.lstat(file)).isSymbolicLink()) throw new Error(`用例不能为符号链接:${item.id}`); + const module = await loadCase(item); + if ( + typeof module?.mount !== 'function' || + typeof module.verify !== 'function' || + (module.exercise !== undefined && typeof module.exercise !== 'function') + ) + throw new Error(`非法用例导出:${item.id}`); + } + return selectCases(cases, { case: caseId }); + } catch (error) { + throw fault('CASE_MANIFEST_INVALID', error.message, error); + } +} +/** 从已验证的冻结清单选择准确范围;目录按层级匹配,不自动扩大或发现文件。 */ +export function selectCases(cases, options = {}) { + if (options.case !== undefined && options.dir !== undefined) throw fault('INVALID_ARGUMENT', '--dir 与 --case 互斥'); + if (options.dir !== undefined && !/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/.test(options.dir)) + throw fault('INVALID_ARGUMENT', '非法用例目录'); + const selected = cases.filter(item => + options.case !== undefined + ? item.id === options.case + : options.dir !== undefined + ? item.file.startsWith(`./${options.dir}/`) + : true + ); + if (!selected.length) throw fault('CASE_MANIFEST_INVALID', `没有匹配用例:${options.dir ?? options.case ?? '全部'}`); + return selected; +} +/** 延迟加载 Playwright,确保帮助和列举不依赖浏览器安装。 */ +export function playwright(root) { + try { + return createRequire(path.join(root, 'packages/vtable/package.json'))('@playwright/test'); + } catch (error) { + throw fault('PREFLIGHT_FAILED', '缺少 Playwright,请先执行 Rush install', error); + } +} +/** 检查本机依赖及浏览器实际启动能力,不下载、不修改依赖。 */ +export async function preflight(root, runtime) { + if (Number(process.versions.node.split('.')[0]) !== 22 || !['darwin', 'linux'].includes(process.platform)) + throw fault('PREFLIGHT_FAILED', '需要 Node.js 22 和 macOS/Linux'); + try { + git(root, ['--version']); + for (const folder of ['tools/bundler', 'packages/vtable']) { + const require = createRequire(path.join(root, folder, 'package.json')); + for (const dependency of folder === 'tools/bundler' + ? ['typescript'] + : ['@internal/bundler/package.json', '@visactor/vutils']) + require.resolve(dependency); + } + playwright(root); + await runtime.run( + process.execPath, + [ + '-e', + 'const {chromium}=require(process.argv[1]);(async()=>{const browser=await chromium.launch();await browser.close();})().catch(e=>{console.error(e);process.exitCode=2;});', + createRequire(path.join(root, 'packages/vtable/package.json')).resolve('@playwright/test') + ], + root, + path.join(root, '.vtable-visual/preflight.log'), + { code: 'PREFLIGHT_FAILED', timeoutMs: 30000 } + ); + return { + playwright: createRequire(path.join(root, 'packages/vtable/package.json'))('@playwright/test/package.json') + .version + }; + } catch (error) { + throw fault( + runtime.interrupted ? 'RUN_INTERRUPTED' : 'PREFLIGHT_FAILED', + `环境未就绪:${error.message}。依赖使用 Rush install;浏览器使用 Playwright install chromium。`, + error + ); + } +} +/** 精确校验结果集合,而非仅以数量相等视为完整。 */ +export function validateResults(result, ids) { + const found = result.tests?.map(item => item.id) ?? []; + if (found.length !== ids.length || new Set(found).size !== found.length || found.some(id => !ids.includes(id))) + throw fault('RESULT_SET_MISMATCH', '阶段结果与选中用例集合不一致'); +} +/** 运行冻结套件的一个阶段,保留已落盘的原始结果供失败汇总。 */ +export async function executePhase(root, runDir, phase, url, ids, runtime) { + const require = createRequire(path.join(root, 'packages/vtable/package.json')); + await fs.rm(path.join(runDir, `${phase}-result.json`), { force: true }); + const code = await runtime.run( + process.execPath, + [require.resolve('@playwright/test/cli'), 'test', '--config', path.join(runDir, 'suite/playwright.config.mjs')], + root, + path.join(runDir, `${phase}.log`), + { + allowFailure: true, + code: 'EXECUTION_FAILED', + env: { VISUAL_RUN_DIR: runDir, VISUAL_BASE_URL: url, VISUAL_PHASE: phase, VISUAL_CASE_IDS: JSON.stringify(ids) } + } + ); + let result; + try { + result = JSON.parse(await fs.readFile(path.join(runDir, `${phase}-result.json`), 'utf8')); + } catch (error) { + throw fault('RESULT_SET_MISMATCH', `${phase} 缺少有效阶段结果`, error); + } + validateResults(result, ids); + if (!result.finalized || result.status === 'error' || (code !== 0 && !(code === 1 && result.status === 'diff'))) + throw fault('EXECUTION_FAILED', `${phase} 阶段执行失败,请查看 ${phase}-result.json 和 ${phase}.log`); + return result; +} +/** 持有锁的运行才能释放锁,避免误删另一次运行。 */ +export async function acquireLock(output, owner) { + const lock = path.join(output, 'running.lock'); + try { + await fs.mkdir(lock); + } catch (error) { + if (error.code === 'EEXIST') throw fault('RUN_LOCKED', `存在运行锁:${lock};检查 owner.json 后再处理陈旧锁`); + throw error; + } + try { + await atomicJson(path.join(lock, 'owner.json'), owner); + } catch (error) { + await fs.rm(lock, { recursive: true, force: true }); + throw error; + } + return async () => { + // 只有身份相同才能清理,陈旧或未知锁不自动接管。 + const current = JSON.parse(await fs.readFile(path.join(lock, 'owner.json'), 'utf8')); + if (current.runId !== owner.runId) throw fault('CLEANUP_FAILED', '运行锁所有权已改变'); + await fs.rm(lock, { recursive: true, force: true }); + }; +} +/** 编排一次完整对比;所有准备失败和清理失败尽可能进入统一报告。 */ +export async function runVisual(root, options) { + const runtime = createRuntime(); + const detach = runtime.listenSignals(); + const output = path.join(root, '.vtable-visual'); + const runId = `${Date.now()}-${randomUUID().slice(0, 8)}`; + const runDir = path.join(output, 'runs', runId); + const report = { + runId, + finalized: false, + status: 'error', + startedAt: new Date().toISOString(), + request: options, + environment: { node: process.version, platform: process.platform, arch: process.arch }, + timings: {}, + cases: [], + issues: [], + stage: 'preparation' + }; + const started = performance.now(); + let releaseLock; + async function timed(name, action) { + // 失败阶段也记录耗时,便于诊断冷启动和中断。 + const start = performance.now(); + try { + return await action(); + } finally { + report.timings[name] = Math.round(performance.now() - start); + } + } + try { + await fs.mkdir(runDir, { recursive: true }); + console.log(`运行目录:${runDir}`); + await atomicJson(path.join(runDir, 'summary.json'), { + ...report, + schemaVersion: 1, + complete: false, + issues: [{ code: 'RUN_INCOMPLETE', message: '运行尚未完成' }] + }); + releaseLock = await acquireLock(output, { runId, pid: process.pid, startedAt: report.startedAt, runDir }); + const suite = path.join(runDir, 'suite'); + const source = path.join(root, 'packages/vtable/__tests__/visual'); + await fileManifest(source); + await fs.cp(source, suite, { recursive: true }); + report.frozenFiles = await fileManifest(suite); + report.suiteDigest = digest(JSON.stringify(report.frozenFiles)); + const { settings } = await import(pathToFileURL(path.join(suite, 'settings.mjs'))); + report.comparison = settings.comparison; + report.environment = { + ...report.environment, + viewport: settings.viewport, + deviceScaleFactor: settings.deviceScaleFactor, + locale: settings.locale, + timezoneId: settings.timezoneId, + fontFamily: settings.fontFamily + }; + const allCases = await loadCases(suite); + const selected = selectCases(allCases, options); + report.selection = { + mode: options.dir !== undefined ? 'directory' : options.case !== undefined ? 'case' : 'all', + value: options.dir ?? options.case ?? null, + selectedIds: selected.map(item => item.id), + selectedCount: selected.length, + totalCount: allCases.length + }; + console.log(`测试范围:${report.selection.value ?? '全部本地用例'};选中 ${selected.length} / ${allCases.length}`); + const names = ['vtable', 'editors', 'gantt', 'plugins', 'sheet', 'vchart'].filter(name => name === 'vtable' || selected.some(item => item.bundles.includes(name))); + if (!names.includes('vtable')) names.unshift('vtable'); + report.cases = selected.map(({ id, purpose, file, sourceExample, bundles }) => ({ + id, + purpose, + sourceExample, + bundles, + source: { + path: `packages/vtable/__tests__/visual/cases/${file.slice(2)}`, + line: 1, + frozenPath: `suite/cases/${file.slice(2)}` + } + })); + report.environment = { ...report.environment, ...(await timed('preflightMs', () => preflight(root, runtime))) }; + await fs.symlink(path.join(root, 'packages/vtable/node_modules'), path.join(runDir, 'node_modules'), 'dir'); + runtime.defer(() => fs.rm(path.join(runDir, 'node_modules'), { force: true })); + report.local = await workingTree(root); + report.stage = 'fetch'; + const log = path.join(runDir, 'build.log'); + const sha = options['self-compare'] + ? report.local.head + : await timed('fetchMs', () => resolveBaseline(root, options.baseline, runtime, log)); + report.baseline = { + repository: options['self-compare'] ? 'working-tree' : official, + requestedRef: options.baseline ?? (options['self-compare'] ? 'working-tree' : 'refs/heads/develop'), + sha, + cacheHit: false + }; + report.stage = 'localBuild'; + console.log('构建当前工作区…'); + await timed('localBuildMs', () => build(root, runDir, 'current', names, runtime, log)); + const after = await workingTree(root); + if (after.head !== report.local.head || after.digest !== report.local.digest) + throw fault('WORKSPACE_CHANGED', '构建期间工作区或 HEAD 发生变化,请重跑'); + report.stage = 'baselineBuild'; + if (options['self-compare']) + for (const name of names) await fs.copyFile(path.join(runDir, `current-${name}.js`), path.join(runDir, `baseline-${name}.js`)); + else await timed('baselineBuildMs', () => baselineBuild(root, runDir, sha, names, runtime, report, timed)); + report.bundles = Object.fromEntries(await Promise.all(names.map(async name => [name, { + baseline: digest(await fs.readFile(path.join(runDir, `baseline-${name}.js`))), + current: digest(await fs.readFile(path.join(runDir, `current-${name}.js`))) + }]))); + const { server, url } = await serve(runDir); + runtime.defer(async () => { + server.closeAllConnections(); + await new Promise(resolve => server.close(resolve)); + }); + const ids = selected.map(item => item.id); + for (const phase of ['baseline', 'current']) { + report.stage = phase; + console.log(`${phase} 截图…`); + report[`${phase}Result`] = await timed(`${phase}ScreenshotsMs`, () => + executePhase(root, runDir, phase, url, ids, runtime) + ); + } + report.status = report.currentResult.status; + } catch (error) { + report.status = 'error'; + const errorCode = error.visualError + ? error.code + : report.stage.endsWith('Build') + ? 'BUILD_FAILED' + : 'EXECUTION_FAILED'; + report.issues.push({ + phase: report.stage, + stage: report.stage, + category: 'execution', + code: errorCode, + message: error.stack ?? String(error) + }); + console.error(`${errorCode}: ${error.message}`); + } finally { + const cleanup = await timed('cleanupMs', () => runtime.cleanup()); + report.issues.push(...cleanup.map(issue => ({ ...issue, phase: 'cleanup', category: 'execution' }))); + if (runtime.interrupted) + report.issues.push({ + phase: report.stage, + category: 'execution', + code: 'RUN_INTERRUPTED', + message: '运行已中断' + }); + if (releaseLock) { + try { + await releaseLock(); + } catch (error) { + report.issues.push({ phase: 'cleanup', category: 'execution', code: 'CLEANUP_FAILED', message: String(error) }); + } + } + detach(); + report.finalized = true; + report.timings.totalMs = Math.round(performance.now() - started); + } + try { + const final = await saveReport(runDir, report); + console.log(`结果:${final.status}\n报告:${path.join(runDir, 'index.html')}`); + return final.status === 'passed' ? 0 : final.status === 'diff' ? 1 : 2; + } catch (error) { + console.error(`REPORT_FAILED: ${error.message};原始证据:${runDir}`); + try { + let evidence = report; + try { + evidence = JSON.parse(await fs.readFile(path.join(runDir, 'summary.json'), 'utf8')); + } catch {} + await atomicJson(path.join(runDir, 'summary.json'), { + ...evidence, + finalized: true, + schemaVersion: 1, + status: 'error', + issues: [ + ...(evidence.issues ?? []), + { phase: 'report', category: 'execution', code: 'REPORT_FAILED', message: String(error) } + ] + }); + } catch {} + try { + await fs.rm(path.join(runDir, 'index.html'), { force: true }); + } catch {} + try { + await fs.writeFile( + path.join(runDir, 'agent-summary.md'), + '# 报告生成失败\n\n状态:error;code:REPORT_FAILED。请读取 summary.json 和阶段日志。\n' + ); + } catch {} + return 2; + } +} diff --git a/packages/vtable/scripts/visual/runtime.mjs b/packages/vtable/scripts/visual/runtime.mjs new file mode 100644 index 0000000000..600ef78e67 --- /dev/null +++ b/packages/vtable/scripts/visual/runtime.mjs @@ -0,0 +1,173 @@ +import { spawn } from 'node:child_process'; +import { createHash, randomUUID } from 'node:crypto'; +import { createServer } from 'node:http'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +/** 携带稳定错误码;错误消息保留具体失败证据。 */ +export function fault(code, message, cause) { + return Object.assign(new Error(message, cause ? { cause } : undefined), { code, visualError: true }); +} +/** 计算输入、产物和缓存的 SHA-256 摘要。 */ +export function digest(value) { + return createHash('sha256').update(value).digest('hex'); +} +/** 同目录写临时文件后替换,避免读到半份结果。 */ +export async function atomicJson(file, value) { + const temporary = `${file}.${randomUUID()}.tmp`; + try { + await fs.writeFile(temporary, JSON.stringify(value, null, 2)); + await fs.rename(temporary, file); + } finally { + await fs.rm(temporary, { force: true }); + } +} +/** 顺序尝试所有清理动作,单项失败不阻断后续回收。 */ +export async function cleanupAll(actions) { + const errors = []; + for (const action of actions.reverse()) { + try { + await action(); + } catch (error) { + errors.push({ code: 'CLEANUP_FAILED', message: String(error) }); + } + } + return errors; +} + +/** 管理单次运行的进程组;只有入口显式调用 listenSignals 才注册处理器。 */ +export function createRuntime() { + const children = new Set(); + const cleanups = []; + let interrupted = false; + let killTimer; + function stop(signal) { + // 仅向本次创建的进程组发送信号。 + for (const child of children) { + if (!child.pid) continue; + try { + process.kill(-child.pid, signal); + } catch (error) { + if (error.code !== 'ESRCH') throw error; + } + } + } + function interrupt() { + // 首先通知退出,三秒后强制终止未退出的子进程。 + interrupted = true; + stop('SIGTERM'); + killTimer ??= setTimeout(() => stop('SIGKILL'), 3000); + killTimer.unref(); + } + return { + get interrupted() { + return interrupted; + }, + defer(action) { + cleanups.push(action); + }, + listenSignals() { + // 返回移除函数,导入和完成运行后均不留下信号监听器。 + process.on('SIGINT', interrupt); + process.on('SIGTERM', interrupt); + return () => { + process.off('SIGINT', interrupt); + process.off('SIGTERM', interrupt); + clearTimeout(killTimer); + }; + }, + async run(command, args, cwd, log, options = {}) { + // 使用参数数组启动命令,保存日志;逾时或中断均为执行错误。 + if (interrupted) throw fault('RUN_INTERRUPTED', '测试已中断'); + const handle = await fs.open(log, 'a'); + let child, timer; + try { + await handle.write(`\n$ ${command} ${args.join(' ')}\n`); + child = spawn(command, args, { + cwd, + env: { + ...process.env, + PATH: `${path.dirname(process.execPath)}:${process.env.PATH}`, + CI: '1', + ...options.env + }, + detached: true, + stdio: ['ignore', handle.fd, handle.fd] + }); + children.add(child); + const code = await new Promise((resolve, reject) => { + child.once('error', reject); + child.once('exit', (code, signal) => resolve(signal ? 2 : code)); + timer = setTimeout(() => reject(fault('TIMEOUT', `命令超时:${log}`)), options.timeoutMs ?? 1200000); + }); + if (interrupted) throw fault('RUN_INTERRUPTED', `运行已中断:${log}`); + if (code !== 0 && !options.allowFailure) + throw fault(options.code ?? 'EXECUTION_FAILED', `命令执行失败 (${code}),请查看 ${log}`); + return code; + } catch (error) { + if (error.visualError) throw error; + throw fault(options.code ?? 'EXECUTION_FAILED', `${error.message};日志:${log}`, error); + } finally { + clearTimeout(timer); + if (child?.pid) { + try { + process.kill(-child.pid, 'SIGKILL'); + } catch {} + } + children.delete(child); + await handle.close(); + } + }, + async cleanup() { + // 即使某个清理函数失败,也继续回收剩余资源。 + const errors = []; + try { + stop('SIGKILL'); + } catch (error) { + errors.push({ code: 'CLEANUP_FAILED', message: String(error) }); + } + errors.push(...(await cleanupAll(cleanups))); + cleanups.length = 0; + return errors; + } + }; +} + +/** 仅暴露冻结套件与两侧构建,使用回环地址及系统分配端口。 */ +export async function serve(runDir) { + const server = createServer(async (request, response) => { + try { + const relative = decodeURIComponent(new URL(request.url, 'http://localhost').pathname).slice(1); + if (!/^(suite\/|(?:baseline|current)-[a-z-]+\.js$)/.test(relative) || relative.split(/[\\/]/).includes('..')) + return response.writeHead(404).end(); + const resolved = await fs.realpath(path.join(runDir, relative)); + if (!resolved.startsWith(`${await fs.realpath(runDir)}${path.sep}`)) return response.writeHead(404).end(); + const content = await fs.readFile(resolved); + response.writeHead(200, { + 'Content-Type': relative.endsWith('.html') ? 'text/html' : 'text/javascript', + 'Cache-Control': 'no-store' + }); + response.end(content); + } catch { + response.writeHead(404).end(); + } + }); + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', resolve); + }); + return { server, url: `http://127.0.0.1:${server.address().port}` }; +} + +/** 按相对路径递归冻结代码资源,不跟随符号链接到工作区外。 */ +export async function fileManifest(directory, relative = '') { + const entries = []; + for (const name of (await fs.readdir(path.join(directory, relative))).sort()) { + const file = path.posix.join(relative, name); + const stat = await fs.lstat(path.join(directory, file)); + if (stat.isSymbolicLink()) throw fault('CASE_MANIFEST_INVALID', `冻结输入不能包含符号链接:${file}`); + if (stat.isDirectory()) entries.push(...(await fileManifest(directory, file))); + else if (stat.isFile()) entries.push({ path: file, digest: digest(await fs.readFile(path.join(directory, file))) }); + } + return entries; +} From bf5728f23a87c381d7d48e9ece441bbbf092cfba Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 14:08:39 +0800 Subject: [PATCH 2/9] test: cover VTable hover selection and frozen edges --- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 111 ++++++++++-------- .../vtable/__tests__/visual/cases/COVERAGE.md | 20 ++-- .../cases/cells/checkbox-header-options.mjs | 44 +++++++ .../cases/frozen/empty-records-header.mjs | 53 +++++++++ .../visual/cases/frozen/frozen-shadow-end.mjs | 46 ++++++++ .../cases/frozen/frozen-shadow-middle.mjs | 46 ++++++++ .../cases/frozen/frozen-shadow-start.mjs | 50 ++++++++ .../cases/frozen/scrollbar-ignore-frozen.mjs | 42 +++++++ .../vtable/__tests__/visual/cases/index.mjs | 15 +++ .../visual/cases/interaction/hover-column.mjs | 61 ++++++++++ .../visual/cases/interaction/hover-cross.mjs | 61 ++++++++++ .../visual/cases/interaction/hover-row.mjs | 61 ++++++++++ .../visual/cases/interaction/hover-single.mjs | 61 ++++++++++ .../interaction/select-column-disabled.mjs | 47 ++++++++ .../cases/interaction/select-drag-outside.mjs | 64 ++++++++++ .../interaction/select-global-disabled.mjs | 44 +++++++ .../cases/interaction/select-header-cell.mjs | 44 +++++++ .../select-header-disabled-drag.mjs | 52 ++++++++ 18 files changed, 866 insertions(+), 56 deletions(-) create mode 100644 packages/vtable/__tests__/visual/cases/cells/checkbox-header-options.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/empty-records-header.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-end.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-middle.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-start.mjs create mode 100644 packages/vtable/__tests__/visual/cases/frozen/scrollbar-ignore-frozen.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/hover-column.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/hover-cross.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/hover-row.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/hover-single.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-column-disabled.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-drag-outside.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-global-disabled.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-header-cell.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-header-disabled-drag.mjs diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 36b3bbb5c7..700929d38e 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -5,11 +5,11 @@ "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, - "deferred_interaction": 176, + "deferred_interaction": 165, "deferred_large_source": 70, "deferred_resource": 31, - "deferred_static": 223, - "migrated": 20, + "deferred_static": 219, + "migrated": 35, "privacy_excluded": 7 }, "entries": [ @@ -169,9 +169,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "hover-cross", + "verification": "表头与表体真实悬停、cross 高亮状态及截图" }, { "id": "647456e55d221c008666ee1d", @@ -238,9 +239,10 @@ "click", "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-drag-outside", + "verification": "单选、拖选、表头选择、表外点击后的范围及截图" }, { "id": "64745a8d5d221c008666ee20", @@ -515,9 +517,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "hover-row", + "verification": "表头与表体真实悬停、row 高亮状态及截图" }, { "id": "647ddbcfeafb6dd17a28869b", @@ -537,9 +540,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "hover-column", + "verification": "表头与表体真实悬停、column 高亮状态及截图" }, { "id": "647ddbf6eafb6dd17a28869c", @@ -559,9 +563,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "hover-single", + "verification": "表头与表体真实悬停、single 高亮状态及截图" }, { "id": "64b780578973e285ed4e5e0c", @@ -1718,9 +1723,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-header-cell", + "verification": "表头点击后单格选择范围及截图" }, { "id": "65322e87159a621b655d9eb9", @@ -2066,9 +2072,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-column-disabled", + "verification": "列级禁选点击后无选择范围及截图" }, { "id": "6544b3b14280163c75d7fa9b", @@ -3438,9 +3445,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-global-disabled", + "verification": "全局禁选点击后无选择范围及截图" }, { "id": "658d56ae20ffa2008c33ebf4", @@ -3463,9 +3471,10 @@ "click", "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-header-disabled-drag", + "verification": "表头禁选点击与真实列拖动后的字段顺序及截图" }, { "id": "658e984a20ffa2008c33ec28", @@ -7466,9 +7475,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "checkbox-header-options", + "verification": "四种复选框列配置、七条状态数据与截图" }, { "id": "6704cd0d22f17300a767a2be", @@ -9557,9 +9567,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "scrollbar-ignore-frozen", + "verification": "动态冻结、setScrollLeft 后主滚动条宽度与截图" }, { "id": "68b012cb8af47900b375bce6", @@ -10707,9 +10718,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "frozen-empty-records-header", + "verification": "311 列末端点击清空记录后左右冻结表头与截图" }, { "id": "6a8597d0a44900005e2b8e47", @@ -10840,9 +10852,10 @@ "click", "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "frozen-shadow-start", + "verification": "横向滚动动作后回到起点;左右阴影可见性与截图" }, { "id": "6aaba81349fc4f005c341b4d", @@ -10861,9 +10874,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "frozen-shadow-end", + "verification": "setScrollLeft 到终点;左右阴影可见性与截图" }, { "id": "6aaba8136d3a95005dc7fa6e", @@ -10882,9 +10896,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "frozen-shadow-middle", + "verification": "setScrollLeft 到中间;左右阴影可见性与截图" } ] } diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 329376964b..136a304adc 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -5,32 +5,36 @@ | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | | 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | -| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | -| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | +| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline`、`checkbox-header-options` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | +| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | | 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | | 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | | Sheet | `sheet-add-columns`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列插入、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | | 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | -| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动 | -| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | +| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | +| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | | 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 ## BugServer 未选候选去向(2026-09-24) -上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 20 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 35 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 20 | 13 个新模块,以匿名数据重建配置及动作 | +| 已迁入本地用例 | 35 | 28 个新模块,以匿名数据重建配置及动作 | | 隐私风险排除 | 7 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 176 | 录制动作缺少对应的本地动作与断言 | -| 静态配置未证明覆盖 | 223 | 配置或数据变体缺少对应的本地断言 | +| 交互未证明覆盖 | 165 | 录制动作缺少对应的本地动作与断言 | +| 静态配置未证明覆盖 | 219 | 配置或数据变体缺少对应的本地断言 | + +新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 + +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。交互目录 16/16 与官方基线通过。 本轮新增可验证场景:列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 diff --git a/packages/vtable/__tests__/visual/cases/cells/checkbox-header-options.mjs b/packages/vtable/__tests__/visual/cases/cells/checkbox-header-options.mjs new file mode 100644 index 0000000000..6532f4d108 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/checkbox-header-options.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 66f689cd33c1e900bc71e36a + * 验证目的:空字段、回调选中、固定选中和禁用配置的复选框表头共同绘制。 + * 改写:保留七种初始状态,其他人员字段改为通用编号。 + */ +export default { + mount(container) { + // 与来源相同地混合列级 headerType、cellType、checked 和 disable。 + return new window.VTable.ListTable(container, { + columns: [ + { field: '', title: '', headerType: 'checkbox', cellType: 'checkbox', width: 60 }, + { field: 'check', title: 'Check', headerType: 'checkbox', cellType: 'checkbox', width: 130, + checked: () => true }, + { field: 'progress', title: 'Progress', headerType: 'checkbox', cellType: 'checkbox', + checked: true, width: 150 }, + { field: 'id', title: 'ID', headerType: 'checkbox', cellType: 'checkbox', + checked: true, disable: true, width: 100 }, + { field: 'label', title: 'Label', width: 150 } + ], + records: [ + { check: { text: 'unchecked', checked: false, disable: false }, progress: 100, id: 1, label: 'A' }, + { check: { text: 'unchecked', checked: false, disable: true }, progress: 80, id: 2, label: 'B' }, + { check: { text: 'checked', checked: true, disable: false }, progress: 1, id: 3, label: 'C' }, + { check: { text: 'checked', checked: true, disable: true }, progress: 55, id: 4, label: 'D' }, + { check: true, progress: 28, id: 5, label: 'E' }, + { check: false, progress: 28, id: 6, label: 'F' }, + { progress: 28, id: 7, label: 'G' } + ], + frozenColCount: 2, allowFrozenColCount: 2, widthMode: 'standard' + }); + }, + async verify(page) { + // 七行、四类复选框列与冻结列必须共同存在,截图验证表头和禁用外观。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.frozenColCount !== 2 || table.colCount !== 5 || table.rowCount !== 8) + throw new Error('复选框列或数据行缺失'); + for (const col of [0, 1, 2, 3]) + if (table.getCellType(col, 1) !== 'checkbox') throw new Error('复选框列类型错误'); + if (table.getCellOriginValue(2, 1) !== 100 || table.getCellOriginValue(1, 7) !== undefined) + throw new Error('初始状态边界缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/empty-records-header.mjs b/packages/vtable/__tests__/visual/cases/frozen/empty-records-header.mjs new file mode 100644 index 0000000000..94063be81e --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/empty-records-header.mjs @@ -0,0 +1,53 @@ +/** + * BugServer case IDs: 6a82f7a71d0efd005e397e9d + * 验证目的:大量列横向滚到末端后,点击触发 setRecords([]) 不应清空冻结表头。 + * 改写:保留 311 列和双侧冻结边界,商品字段替换成编号与通用数值。 + */ +export default { + mount(container) { + // 311 列保留来源的横向虚拟化压力,六条匿名记录足以触发空记录更新。 + container.style.width = '900px'; + container.style.height = '420px'; + const columns = Array.from({ length: 311 }, (_, col) => ({ + field: 'c' + col, title: 'Field ' + col, width: col < 11 ? 'auto' : 120 + })); + const records = Array.from({ length: 6 }, (_, row) => + Object.fromEntries(columns.map((column, col) => [column.field, row * 1000 + col]))); + const table = new window.VTable.ListTable(container, { + columns, records, frozenRowCount: 3, bottomFrozenRowCount: 1, + frozenColCount: 2, rightFrozenColCount: 2, widthMode: 'standard', + rowSeriesNumber: { width: 50, format: () => '', cellType: 'checkbox', headerType: 'checkbox' } + }); + let triggered = false; + table.on('click_cell', () => { + // 保留来源的点击触发路径,只执行一次空记录更新。 + if (triggered) return; + triggered = true; + table.setScrollLeft(100000); + table.setRecords([]); + }); + return table; + }, + async exercise(page) { + // 先远距离横向滚动,再点击左冻结表体格触发 setRecords([])。 + await page.evaluate(() => window.__visualTable.setScrollLeft(100000)); + await page.waitForFunction(() => window.__visualTable.scrollLeft > 0); + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + await page.waitForFunction(() => window.__visualTable.records.length === 0); + }, + async verify(page) { + // 空记录更新后左右两侧表头仍有字段,截图检查中间表头绘制。 + await page.evaluate(() => { + const table = window.__visualTable; + const left = table.getCellValue(1, 0); + const right = table.getCellValue(table.colCount - 1, 0); + if (table.records.length !== 0 || !left || !right || table.colCount < 300) + throw new Error('空记录更新后冻结表头丢失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-end.mjs b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-end.mjs new file mode 100644 index 0000000000..5525ee481c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-end.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 6aaba81349fc4f005c341b4d + * 验证目的:横向滚动到 end 时,冻结列阴影仅在存在溢出的一侧显示。 + * 改写:保留来源的 10 列宽度与 overflow 阴影配置,单元格只用通用编号。 + */ +export default { + mount(container) { + // 580px 容器、左右各一冻结列产生可见的中间横向滚动区。 + container.style.width = '580px'; + container.style.height = '420px'; + const columns = Array.from({ length: 10 }, (_, col) => ({ field: 'c' + col, title: 'Column ' + (col + 1), width: 140 })); + const records = Array.from({ length: 8 }, (_, row) => + Object.fromEntries(columns.map((column, col) => [column.field, 'R' + (row + 1) + ' / C' + (col + 1)]))); + return new window.VTable.ListTable(container, { + columns, records, frozenColCount: 1, rightFrozenColCount: 1, + defaultRowHeight: 42, defaultHeaderRowHeight: 44, widthMode: 'standard', + theme: window.VTable.themes.DEFAULT.extends({ + frozenColumnLine: { shadow: { width: 18, startColor: 'rgba(34, 78, 138, 0.58)', + endColor: 'rgba(34, 78, 138, 0)', visible: 'overflow' } } + }) + }); + }, + async exercise(page) { + // 与来源相同地用 setScrollLeft 定位;起点用例额外重放横向滚动后回到起点。 + await page.evaluate(() => window.__visualTable.setScrollLeft(Number.MAX_SAFE_INTEGER)); + + await page.waitForFunction(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + return left === expected.left && right === expected.right; + }, { left: true, right: false }); + }, + async verify(page) { + // 检查滚动位置、冻结列数和阴影实际可见状态,截图负责颜色及边界。 + await page.evaluate(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + if (table.frozenColCount !== 1 || table.rightFrozenColCount !== 1 || + left !== expected.left || right !== expected.right || + (expected.position === 'start' ? table.scrollLeft !== 0 : table.scrollLeft <= 0)) + throw new Error('冻结阴影溢出状态错误'); + }, { left: true, right: false, position: 'end' }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-middle.mjs b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-middle.mjs new file mode 100644 index 0000000000..6add3e3b4a --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-middle.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 6aaba8136d3a95005dc7fa6e + * 验证目的:横向滚动到 middle 时,冻结列阴影仅在存在溢出的一侧显示。 + * 改写:保留来源的 10 列宽度与 overflow 阴影配置,单元格只用通用编号。 + */ +export default { + mount(container) { + // 580px 容器、左右各一冻结列产生可见的中间横向滚动区。 + container.style.width = '580px'; + container.style.height = '420px'; + const columns = Array.from({ length: 10 }, (_, col) => ({ field: 'c' + col, title: 'Column ' + (col + 1), width: 140 })); + const records = Array.from({ length: 8 }, (_, row) => + Object.fromEntries(columns.map((column, col) => [column.field, 'R' + (row + 1) + ' / C' + (col + 1)]))); + return new window.VTable.ListTable(container, { + columns, records, frozenColCount: 1, rightFrozenColCount: 1, + defaultRowHeight: 42, defaultHeaderRowHeight: 44, widthMode: 'standard', + theme: window.VTable.themes.DEFAULT.extends({ + frozenColumnLine: { shadow: { width: 18, startColor: 'rgba(34, 78, 138, 0.58)', + endColor: 'rgba(34, 78, 138, 0)', visible: 'overflow' } } + }) + }); + }, + async exercise(page) { + // 与来源相同地用 setScrollLeft 定位;起点用例额外重放横向滚动后回到起点。 + await page.evaluate(() => window.__visualTable.setScrollLeft(280)); + + await page.waitForFunction(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + return left === expected.left && right === expected.right; + }, { left: true, right: true }); + }, + async verify(page) { + // 检查滚动位置、冻结列数和阴影实际可见状态,截图负责颜色及边界。 + await page.evaluate(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + if (table.frozenColCount !== 1 || table.rightFrozenColCount !== 1 || + left !== expected.left || right !== expected.right || + (expected.position === 'start' ? table.scrollLeft !== 0 : table.scrollLeft <= 0)) + throw new Error('冻结阴影溢出状态错误'); + }, { left: true, right: true, position: 'middle' }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-start.mjs b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-start.mjs new file mode 100644 index 0000000000..976e3a89db --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/frozen-shadow-start.mjs @@ -0,0 +1,50 @@ +/** + * BugServer case IDs: 6aaba81349fc4f005c341b4c + * 验证目的:横向滚动到 start 时,冻结列阴影仅在存在溢出的一侧显示。 + * 改写:保留来源的 10 列宽度与 overflow 阴影配置,单元格只用通用编号。 + */ +export default { + mount(container) { + // 580px 容器、左右各一冻结列产生可见的中间横向滚动区。 + container.style.width = '580px'; + container.style.height = '420px'; + const columns = Array.from({ length: 10 }, (_, col) => ({ field: 'c' + col, title: 'Column ' + (col + 1), width: 140 })); + const records = Array.from({ length: 8 }, (_, row) => + Object.fromEntries(columns.map((column, col) => [column.field, 'R' + (row + 1) + ' / C' + (col + 1)]))); + return new window.VTable.ListTable(container, { + columns, records, frozenColCount: 1, rightFrozenColCount: 1, + defaultRowHeight: 42, defaultHeaderRowHeight: 44, widthMode: 'standard', + theme: window.VTable.themes.DEFAULT.extends({ + frozenColumnLine: { shadow: { width: 18, startColor: 'rgba(34, 78, 138, 0.58)', + endColor: 'rgba(34, 78, 138, 0)', visible: 'overflow' } } + }) + }); + }, + async exercise(page) { + // 与来源相同地用 setScrollLeft 定位;起点用例额外重放横向滚动后回到起点。 + await page.evaluate(() => window.__visualTable.setScrollLeft(0)); + const host = await page.locator('#table').boundingBox(); + await page.mouse.move(host.x + 280, host.y + 100); + await page.mouse.wheel(280, 0); + await page.waitForFunction(() => window.__visualTable.scrollLeft > 0); + await page.evaluate(() => window.__visualTable.setScrollLeft(0)); + await page.waitForFunction(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + return left === expected.left && right === expected.right; + }, { left: false, right: true }); + }, + async verify(page) { + // 检查滚动位置、冻结列数和阴影实际可见状态,截图负责颜色及边界。 + await page.evaluate(expected => { + const table = window.__visualTable; + const left = table.scenegraph.component.frozenShadowLine.attribute.visible; + const right = table.scenegraph.component.rightFrozenShadowLine.attribute.visible; + if (table.frozenColCount !== 1 || table.rightFrozenColCount !== 1 || + left !== expected.left || right !== expected.right || + (expected.position === 'start' ? table.scrollLeft !== 0 : table.scrollLeft <= 0)) + throw new Error('冻结阴影溢出状态错误'); + }, { left: false, right: true, position: 'start' }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/frozen/scrollbar-ignore-frozen.mjs b/packages/vtable/__tests__/visual/cases/frozen/scrollbar-ignore-frozen.mjs new file mode 100644 index 0000000000..2984804434 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/frozen/scrollbar-ignore-frozen.mjs @@ -0,0 +1,42 @@ +/** + * BugServer case IDs: 68a2e109fcb96500a7134dd7 + * 验证目的:运行时设置冻结列和横向滚动后,ignoreFrozenCols 使主滚动条跨完整表宽。 + * 改写:重复人员列替换成编号列,保留来源的尺寸、主题和 API 调用。 + */ +export default { + mount(container) { + // 固定七列使主体溢出,后续再按来源动态设置冻结列数。 + container.style.width = '800px'; + container.style.height = '400px'; + const columns = Array.from({ length: 7 }, (_, col) => ({ field: 'c' + col, title: 'Column ' + col, width: col === 0 ? 150 : 200 })); + const table = new window.VTable.ListTable(container, { + columns, widthMode: 'standard', frozenColCount: 0, + theme: { + frozenColumnLine: { shadow: { width: 24, startColor: 'rgba(0, 24, 47, 0.06)', endColor: 'rgba(0, 24, 47, 0)' } }, + scrollStyle: { visible: 'always', ignoreFrozenCols: true } + } + }); + table.setRecords(Array.from({ length: 5 }, (_, row) => + Object.fromEntries(columns.map((column, col) => [column.field, row * 10 + col])))); + return table; + }, + async exercise(page) { + // 与来源相同地动态设置冻结列数,再滚动到横向中间位置。 + await page.evaluate(() => { + const table = window.__visualTable; + table.frozenColCount = 2; + table.setScrollLeft(200); + }); + await page.waitForFunction(() => window.__visualTable.scrollLeft === 200); + }, + async verify(page) { + // 滚动条总宽必须包含冻结区,主体内容也必须已滚动。 + await page.evaluate(() => { + const table = window.__visualTable; + const bar = table.scenegraph.component.hScrollBar.attribute; + if (table.frozenColCount !== 2 || table.scrollLeft !== 200 || + !table.theme.scrollStyle.ignoreFrozenCols || bar.width < table.tableNoFrameWidth - 5) + throw new Error('冻结列仍被主滚动条排除'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index 1acc16a663..a9affb3ebe 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -157,6 +157,21 @@ export const cases = [ { id: 'pivot-corner-remaining-variants', purpose: '角头其余三种行列指标排列', file: './pivot/corner-remaining-variants.mjs', bundles: ['vtable'] }, { id: 'pivot-resize-indicator-group', purpose: '指标组行高按比例一起拖动', file: './pivot/resize-indicator-group.mjs', bundles: ['vtable'] }, { id: 'transpose-only-body-auto-width', purpose: '转置表仅按表体计算自动列宽', file: './transpose/only-body-auto-width.mjs', bundles: ['vtable'] }, + { id: 'hover-cross', purpose: '表头与表体悬停的 cross 高亮模式', file: './interaction/hover-cross.mjs', bundles: ['vtable'] }, + { id: 'hover-row', purpose: '表头与表体悬停的 row 高亮模式', file: './interaction/hover-row.mjs', bundles: ['vtable'] }, + { id: 'hover-column', purpose: '表头与表体悬停的 column 高亮模式', file: './interaction/hover-column.mjs', bundles: ['vtable'] }, + { id: 'hover-single', purpose: '表头与表体悬停的 single 高亮模式', file: './interaction/hover-single.mjs', bundles: ['vtable'] }, + { id: 'select-drag-outside', purpose: '连续单选拖选表头选择与表外清选', file: './interaction/select-drag-outside.mjs', bundles: ['vtable'] }, + { id: 'select-header-cell', purpose: '表头 cell 模式单格选择', file: './interaction/select-header-cell.mjs', bundles: ['vtable'] }, + { id: 'select-column-disabled', purpose: '列级表体与表头禁选', file: './interaction/select-column-disabled.mjs', bundles: ['vtable'] }, + { id: 'select-global-disabled', purpose: '全局禁选表体与表头', file: './interaction/select-global-disabled.mjs', bundles: ['vtable'] }, + { id: 'select-header-disabled-drag', purpose: '表头禁选下的表体选择与列拖动', file: './interaction/select-header-disabled-drag.mjs', bundles: ['vtable'] }, + { id: 'frozen-shadow-start', purpose: '冻结列 overflow 阴影在 start 位置的可见性', file: './frozen/frozen-shadow-start.mjs', bundles: ['vtable'] }, + { id: 'frozen-shadow-end', purpose: '冻结列 overflow 阴影在 end 位置的可见性', file: './frozen/frozen-shadow-end.mjs', bundles: ['vtable'] }, + { id: 'frozen-shadow-middle', purpose: '冻结列 overflow 阴影在 middle 位置的可见性', file: './frozen/frozen-shadow-middle.mjs', bundles: ['vtable'] }, + { id: 'scrollbar-ignore-frozen', purpose: '主横向滚动条跨越冻结列宽度', file: './frozen/scrollbar-ignore-frozen.mjs', bundles: ['vtable'] }, + { id: 'frozen-empty-records-header', purpose: '大量列滚动后清空记录保留冻结表头', file: './frozen/empty-records-header.mjs', bundles: ['vtable'] }, + { id: 'checkbox-header-options', purpose: '复选框表头回调固定选中与禁用配置', file: './cells/checkbox-header-options.mjs', bundles: ['vtable'] }, ]; /** 从当前清单目录加载用例,冻结副本不会回到工作区取代码。 */ diff --git a/packages/vtable/__tests__/visual/cases/interaction/hover-column.mjs b/packages/vtable/__tests__/visual/cases/interaction/hover-column.mjs new file mode 100644 index 0000000000..a0c2e39d24 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/hover-column.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 647ddbcfeafb6dd17a28869b + * 验证目的:录制的表头与表体悬停触发 column 高亮模式。 + * 改写:以单元格矩形代替旧录制坐标,固定公开记录和颜色。 + */ +export default { + mount(container) { + // 固定同一组列和记录,仅切换来源的 hover 模式与表头禁用项。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A' }, + { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' } + ], + showPin: true, + allowFrozenColCount: 2, + widthMode: 'standard', + hover: { highlightMode: 'column', disableHover: false, disableHeaderHover: true }, + theme: { + bodyStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } }, + headerStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } } + } + }); + }, + async exercise(page) { + // 先执行录制的表头悬停,再移动到表体,保留最终高亮供截图比较。 + const cellPoint = row => page.evaluate(row => { + const b = window.__visualTable.getCellRect(1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, row); + await page.mouse.move(850, 60); + const header = await cellPoint(0); + await page.mouse.move(header.x, header.y); + await page.waitForFunction(disabled => { + const hover = window.__visualTable.stateManager.hover; + return hover.disableHeader === disabled && (disabled || hover.cellPos.row === 0); + }, true); + const body = await cellPoint(2); + await page.mouse.move(body.x, body.y); + await page.waitForFunction(() => { + const pos = window.__visualTable.stateManager.hover.cellPos; + return pos.col === 1 && pos.row === 2; + }); + }, + async verify(page) { + // 模式与真实悬停位置必须一致,截图验证着色范围。 + await page.evaluate(expected => { + const table = window.__visualTable; + const hover = table.stateManager.hover; + if (hover.highlightScope !== expected || hover.cellPos.col !== 1 || hover.cellPos.row !== 2) + throw new Error('悬停高亮模式或位置错误'); + if (table.getCellOriginValue(1, 2) !== 2) throw new Error('测试数据缺失'); + }, 'column'); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/hover-cross.mjs b/packages/vtable/__tests__/visual/cases/interaction/hover-cross.mjs new file mode 100644 index 0000000000..7db485162f --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/hover-cross.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 6474561b5d221c008666ee1c + * 验证目的:录制的表头与表体悬停触发 cross 高亮模式。 + * 改写:以单元格矩形代替旧录制坐标,固定公开记录和颜色。 + */ +export default { + mount(container) { + // 固定同一组列和记录,仅切换来源的 hover 模式与表头禁用项。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A' }, + { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' } + ], + showPin: true, + allowFrozenColCount: 2, + widthMode: 'standard', + hover: { highlightMode: 'cross', disableHover: false, disableHeaderHover: true }, + theme: { + bodyStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } }, + headerStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } } + } + }); + }, + async exercise(page) { + // 先执行录制的表头悬停,再移动到表体,保留最终高亮供截图比较。 + const cellPoint = row => page.evaluate(row => { + const b = window.__visualTable.getCellRect(1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, row); + await page.mouse.move(850, 60); + const header = await cellPoint(0); + await page.mouse.move(header.x, header.y); + await page.waitForFunction(disabled => { + const hover = window.__visualTable.stateManager.hover; + return hover.disableHeader === disabled && (disabled || hover.cellPos.row === 0); + }, true); + const body = await cellPoint(2); + await page.mouse.move(body.x, body.y); + await page.waitForFunction(() => { + const pos = window.__visualTable.stateManager.hover.cellPos; + return pos.col === 1 && pos.row === 2; + }); + }, + async verify(page) { + // 模式与真实悬停位置必须一致,截图验证着色范围。 + await page.evaluate(expected => { + const table = window.__visualTable; + const hover = table.stateManager.hover; + if (hover.highlightScope !== expected || hover.cellPos.col !== 1 || hover.cellPos.row !== 2) + throw new Error('悬停高亮模式或位置错误'); + if (table.getCellOriginValue(1, 2) !== 2) throw new Error('测试数据缺失'); + }, 'cross'); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/hover-row.mjs b/packages/vtable/__tests__/visual/cases/interaction/hover-row.mjs new file mode 100644 index 0000000000..295024387b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/hover-row.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 647ddbb8733d2ab935925356 + * 验证目的:录制的表头与表体悬停触发 row 高亮模式。 + * 改写:以单元格矩形代替旧录制坐标,固定公开记录和颜色。 + */ +export default { + mount(container) { + // 固定同一组列和记录,仅切换来源的 hover 模式与表头禁用项。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A' }, + { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' } + ], + showPin: true, + allowFrozenColCount: 2, + widthMode: 'standard', + hover: { highlightMode: 'row', disableHover: false, disableHeaderHover: true }, + theme: { + bodyStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } }, + headerStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } } + } + }); + }, + async exercise(page) { + // 先执行录制的表头悬停,再移动到表体,保留最终高亮供截图比较。 + const cellPoint = row => page.evaluate(row => { + const b = window.__visualTable.getCellRect(1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, row); + await page.mouse.move(850, 60); + const header = await cellPoint(0); + await page.mouse.move(header.x, header.y); + await page.waitForFunction(disabled => { + const hover = window.__visualTable.stateManager.hover; + return hover.disableHeader === disabled && (disabled || hover.cellPos.row === 0); + }, true); + const body = await cellPoint(2); + await page.mouse.move(body.x, body.y); + await page.waitForFunction(() => { + const pos = window.__visualTable.stateManager.hover.cellPos; + return pos.col === 1 && pos.row === 2; + }); + }, + async verify(page) { + // 模式与真实悬停位置必须一致,截图验证着色范围。 + await page.evaluate(expected => { + const table = window.__visualTable; + const hover = table.stateManager.hover; + if (hover.highlightScope !== expected || hover.cellPos.col !== 1 || hover.cellPos.row !== 2) + throw new Error('悬停高亮模式或位置错误'); + if (table.getCellOriginValue(1, 2) !== 2) throw new Error('测试数据缺失'); + }, 'row'); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/hover-single.mjs b/packages/vtable/__tests__/visual/cases/interaction/hover-single.mjs new file mode 100644 index 0000000000..b3137d10c3 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/hover-single.mjs @@ -0,0 +1,61 @@ +/** + * BugServer case IDs: 647ddbf6eafb6dd17a28869c + * 验证目的:录制的表头与表体悬停触发 single 高亮模式。 + * 改写:以单元格矩形代替旧录制坐标,固定公开记录和颜色。 + */ +export default { + mount(container) { + // 固定同一组列和记录,仅切换来源的 hover 模式与表头禁用项。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A' }, + { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' } + ], + showPin: true, + allowFrozenColCount: 2, + widthMode: 'standard', + hover: { highlightMode: 'single', disableHover: false, disableHeaderHover: false }, + theme: { + bodyStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } }, + headerStyle: { hover: { cellBgColor: '#CCE0FF', inlineRowBgColor: '#F3F8FF', inlineColumnBgColor: '#F3F8FF' } } + } + }); + }, + async exercise(page) { + // 先执行录制的表头悬停,再移动到表体,保留最终高亮供截图比较。 + const cellPoint = row => page.evaluate(row => { + const b = window.__visualTable.getCellRect(1, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, row); + await page.mouse.move(850, 60); + const header = await cellPoint(0); + await page.mouse.move(header.x, header.y); + await page.waitForFunction(disabled => { + const hover = window.__visualTable.stateManager.hover; + return hover.disableHeader === disabled && (disabled || hover.cellPos.row === 0); + }, false); + const body = await cellPoint(2); + await page.mouse.move(body.x, body.y); + await page.waitForFunction(() => { + const pos = window.__visualTable.stateManager.hover.cellPos; + return pos.col === 1 && pos.row === 2; + }); + }, + async verify(page) { + // 模式与真实悬停位置必须一致,截图验证着色范围。 + await page.evaluate(expected => { + const table = window.__visualTable; + const hover = table.stateManager.hover; + if (hover.highlightScope !== expected || hover.cellPos.col !== 1 || hover.cellPos.row !== 2) + throw new Error('悬停高亮模式或位置错误'); + if (table.getCellOriginValue(1, 2) !== 2) throw new Error('测试数据缺失'); + }, 'single'); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-column-disabled.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-column-disabled.mjs new file mode 100644 index 0000000000..c5cf5aa68d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-column-disabled.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6544ad1a4280163c75d7fa98 + * 验证目的:列级 disableSelect 与 disableHeaderSelect 分别阻止表体和表头选择。 + * 改写:将录制坐标换成固定单元格矩形,记录改为公开数据。 + */ +export default { + mount(container) { + // 保留来源的选择与列级配置,使用同一组固定数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true, disableSelect: true }, + { field: 'id', title: 'ID', width: 100, disableHeaderSelect: true }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }, { progress: 1, id: 3, name: 'C' }], + widthMode: 'standard', + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff' } }, + hover: { highlightMode: 'cross', disableHeaderHover: true }, + select: { } + }); + }, + async exercise(page) { + // 重放来源的表体和表头点击,并逐步核对选择结果。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(0, 1); + await page.waitForTimeout(100); + if (await page.evaluate(() => window.__visualTable.getSelectedCellRanges().length)) + throw new Error('禁选表体列仍被选中'); + await click(1, 0); + await page.waitForTimeout(100); + }, + async verify(page) { + // 最终语义状态与截图中的选择外观应对应。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getSelectedCellRanges().length) throw new Error('禁选表头仍被选中'); + if (table.getCellOriginValue(1, 1) !== 1) throw new Error('测试数据缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-drag-outside.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-drag-outside.mjs new file mode 100644 index 0000000000..3a61f25bad --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-drag-outside.mjs @@ -0,0 +1,64 @@ +/** + * BugServer case IDs: 64745a465d221c008666ee1f + * 验证目的:普通、拖动、表头和外部点击依次保留预期选择范围及自定义样式。 + * 改写:用单元格矩形执行录制动作,记录改为固定公开数据。 + */ +export default { + mount(container) { + // 保留来源的选择样式、表头排序入口和悬停配置。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [ + { progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }, + { progress: 1, id: 3, name: 'C' }, { progress: 55, id: 4, name: 'D' } + ], + showPin: true, + allowFrozenColCount: 2, + widthMode: 'standard', + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff' } }, + hover: { highlightMode: 'cross', disableHover: false, disableHeaderHover: true } + }); + }, + async exercise(page) { + // 按来源顺序执行单选、拖选、表头选择、再次拖选和表外点击。 + const point = (col, row) => page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + const drag = async (start, end) => { + await page.mouse.move(start.x, start.y); + await page.mouse.down(); + await page.mouse.move(end.x, end.y, { steps: 8 }); + await page.mouse.up(); + }; + const first = await point(0, 1); + await page.mouse.click(first.x, first.y); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 1); + await drag(await point(0, 2), await point(2, 3)); + await page.waitForFunction(() => { + const range = window.__visualTable.getSelectedCellRanges()[0]; + return range && range.end.col - range.start.col >= 2 && range.end.row - range.start.row >= 1; + }); + const header = await point(1, 0); + await page.mouse.click(header.x, header.y); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 0); + await drag(await point(0, 1), await point(2, 3)); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.end.col >= 2); + await page.mouse.click(850, 650); + }, + async verify(page) { + // 来源的表外点击不清除已选区域,最终范围和选择样式由截图共同验证。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellOriginValue(0, 1) !== 100) throw new Error('记录数据缺失'); + if (table.theme.selectionStyle?.cellBorderColor !== '#0000ff') throw new Error('选择样式未应用'); + const range = table.getSelectedCellRanges()[0]; + if (!range || range.end.col < 2 || range.end.row < 3) throw new Error('表外点击后选择范围丢失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-global-disabled.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-global-disabled.mjs new file mode 100644 index 0000000000..7350b7efeb --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-global-disabled.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 658d566a20ffa2008c33ebf1 + * 验证目的:全局 disableSelect 阻止表体和表头点击生成选择范围。 + * 改写:将录制坐标换成固定单元格矩形,记录改为公开数据。 + */ +export default { + mount(container) { + // 保留来源的选择与列级配置,使用同一组固定数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }, { progress: 1, id: 3, name: 'C' }], + widthMode: 'standard', + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff' } }, + hover: { highlightMode: 'cross', disableHeaderHover: true }, + select: { disableSelect: true } + }); + }, + async exercise(page) { + // 重放来源的表体和表头点击,并逐步核对选择结果。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(2, 1); + await click(2, 0); + await page.waitForTimeout(100); + }, + async verify(page) { + // 最终语义状态与截图中的选择外观应对应。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getSelectedCellRanges().length) throw new Error('全局禁选仍产生选择范围'); + if (!table.options.select?.disableSelect) throw new Error('全局禁选配置未应用'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-header-cell.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-header-cell.mjs new file mode 100644 index 0000000000..a9c11e2598 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-header-cell.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 653102ad8632117ed798a270 + * 验证目的:headerSelectMode 为 cell 时,点击表头只选中该表头格。 + * 改写:将录制坐标换成固定单元格矩形,记录改为公开数据。 + */ +export default { + mount(container) { + // 保留来源的选择与列级配置,使用同一组固定数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, name: 'A' }, { progress: 80, id: 2, name: 'B' }, { progress: 1, id: 3, name: 'C' }], + widthMode: 'standard', + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff' } }, + hover: { highlightMode: 'cross', disableHeaderHover: true }, + select: { headerSelectMode: 'cell' } + }); + }, + async exercise(page) { + // 重放来源的表体和表头点击,并逐步核对选择结果。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(2, 0); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.col === 2); + }, + async verify(page) { + // 最终语义状态与截图中的选择外观应对应。 + await page.evaluate(() => { + const table = window.__visualTable; + const range = table.getSelectedCellRanges()[0]; + if (!range || range.start.col !== 2 || range.end.col !== 2 || range.start.row !== 0 || range.end.row !== 0) + throw new Error('表头未保持单格选择'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-header-disabled-drag.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-header-disabled-drag.mjs new file mode 100644 index 0000000000..6cf004b9d7 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-header-disabled-drag.mjs @@ -0,0 +1,52 @@ +/** + * BugServer case IDs: 658d56ae20ffa2008c33ebf4 + * 验证目的:表头禁选时,表体点击仍可选择,列头仍可拖动重排。 + * 改写:使用固定四列和单元格矩形复现点击与拖动顺序。 + */ +export default { + mount(container) { + // 同时启用全列拖动与表头禁选,观察两个交互是否互相影响。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, showSort: true }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'code', title: 'Code', width: 150 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 100, id: 1, code: 'A1', name: 'A' }, { progress: 80, id: 2, code: 'B2', name: 'B' }], + widthMode: 'standard', + dragHeaderMode: 'all', + select: { disableHeaderSelect: true }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 先点击表体与禁选表头,再按来源把 ID 列拖向 Name 列。 + const point = (col, row) => page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + const body = await point(2, 1); + await page.mouse.click(body.x, body.y); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 1); + const codeHeader = await point(2, 0); + await page.mouse.click(codeHeader.x, codeHeader.y); + if (await page.evaluate(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 0)) + throw new Error('禁选表头被选中'); + const start = await point(1, 0); + const end = await point(3, 0); + await page.mouse.move(start.x, start.y); + await page.mouse.down(); + await page.mouse.move(end.x, end.y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // ID 列必须离开原位置;表体选择已在拖动前单独检查。 + await page.evaluate(() => { + const table = window.__visualTable; + const fields = Array.from({ length: table.colCount }, (_, col) => table.getHeaderField(col, 0)); + if (fields.indexOf('id') <= 1) throw new Error('禁选表头阻断了列拖动'); + }); + } +}; From dbab3fde6871b8627c764d24a1c7dee16876f0c7 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 14:30:51 +0800 Subject: [PATCH 3/9] test: cover selection modes and run visual regression in CI --- .github/workflows/vtable-visual.yml | 44 +++++++++++++ .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 61 ++++++++++--------- .../vtable/__tests__/visual/cases/COVERAGE.md | 18 +++--- .../visual/cases/api/change-cell-values.mjs | 44 +++++++++++++ .../vtable/__tests__/visual/cases/index.mjs | 6 ++ .../interaction/select-highlight-column.mjs | 45 ++++++++++++++ .../select-highlight-cross-header-cell.mjs | 46 ++++++++++++++ .../select-highlight-cross-theme.mjs | 46 ++++++++++++++ .../select-highlight-cross-transpose.mjs | 47 ++++++++++++++ .../interaction/select-highlight-row.mjs | 45 ++++++++++++++ 10 files changed, 367 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/vtable-visual.yml create mode 100644 packages/vtable/__tests__/visual/cases/api/change-cell-values.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-column.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-header-cell.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-theme.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-transpose.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-row.mjs diff --git a/.github/workflows/vtable-visual.yml b/.github/workflows/vtable-visual.yml new file mode 100644 index 0000000000..d980d89a16 --- /dev/null +++ b/.github/workflows/vtable-visual.yml @@ -0,0 +1,44 @@ +name: VTable visual regression + +on: + pull_request: + branches: [develop] + paths: + - .github/workflows/vtable-visual.yml + - packages/vtable/** + - packages/vtable-editors/** + - packages/vtable-gantt/** + - packages/vtable-plugins/** + - packages/vtable-sheet/** + - tools/bundler/** + - common/config/rush/** + workflow_dispatch: + +permissions: + contents: read + +jobs: + visual: + runs-on: macos-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install dependencies + run: node common/scripts/install-run-rush.js install --ignore-hooks + - name: Install Chromium + run: node packages/vtable/node_modules/@playwright/test/cli.js install chromium + - name: Check visual runner + run: node --test packages/vtable/scripts/visual-test.test.mjs + - name: Compare with official develop + run: node packages/vtable/scripts/visual-test.mjs + - name: Upload failure report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: vtable-visual-report + path: .vtable-visual/runs/ + if-no-files-found: ignore + retention-days: 7 diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 700929d38e..4cece6c0d1 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -5,12 +5,12 @@ "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, - "deferred_interaction": 165, + "deferred_interaction": 160, "deferred_large_source": 70, "deferred_resource": 31, - "deferred_static": 219, - "migrated": 35, - "privacy_excluded": 7 + "deferred_static": 216, + "migrated": 40, + "privacy_excluded": 10 }, "entries": [ { @@ -3691,9 +3691,9 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" }, { "id": "659e667c6040570085cd3eea", @@ -4738,9 +4738,9 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" }, { "id": "65e69335603de700d1d8b9e6", @@ -4836,9 +4836,9 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" }, { "id": "65e7d4da603de700d1d8ba3d", @@ -5759,9 +5759,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-row", + "verification": "body/header click order + selected range + highlightScope + visual theme" }, { "id": "665eb726faec2700ad74954d", @@ -5782,9 +5783,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-column", + "verification": "body/header click order + selected range + highlightScope + visual theme" }, { "id": "665eb7fafaec2700ad749551", @@ -5805,9 +5807,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-cross-theme", + "verification": "body/header click order + selected range + highlightScope + visual theme" }, { "id": "665eba0ca4737f00b6623d44", @@ -5829,9 +5832,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-cross-header-cell", + "verification": "body/header click order + selected range + highlightScope + visual theme" }, { "id": "665ecceafaec2700ad749556", @@ -5854,9 +5858,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-cross-transpose", + "verification": "body/header click order + selected range + highlightScope + visual theme" }, { "id": "665ecf14faec2700ad749559", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 136a304adc..160db0c9b5 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -12,28 +12,32 @@ | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | | Sheet | `sheet-add-columns`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列插入、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | | 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | -| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | -| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | +| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | +| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | | 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 ## BugServer 未选候选去向(2026-09-24) -上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 35 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 40 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 35 | 28 个新模块,以匿名数据重建配置及动作 | -| 隐私风险排除 | 7 | 发现业务化字段或数值,原始内容没有进入仓库 | +| 已迁入本地用例 | 40 | 33 个新模块,以匿名数据重建配置及动作 | +| 隐私风险排除 | 10 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 165 | 录制动作缺少对应的本地动作与断言 | -| 静态配置未证明覆盖 | 219 | 配置或数据变体缺少对应的本地断言 | +| 交互未证明覆盖 | 160 | 录制动作缺少对应的本地动作与断言 | +| 静态配置未证明覆盖 | 216 | 配置或数据变体缺少对应的本地断言 | + +三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除,独立的 `api-change-cell-values` 用匿名固定记录验证二维更新,不关联这些来源 ID。 新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 +继续补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,逐例保留真实来源 ID,验证表头/表体点击顺序与最终选择范围。 + 新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。交互目录 16/16 与官方基线通过。 本轮新增可验证场景:列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 diff --git a/packages/vtable/__tests__/visual/cases/api/change-cell-values.mjs b/packages/vtable/__tests__/visual/cases/api/change-cell-values.mjs new file mode 100644 index 0000000000..3dc2b94183 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/api/change-cell-values.mjs @@ -0,0 +1,44 @@ +/** + * 验证目的:匿名二维批量单元格更新保持行列映射,并让相邻单元格不变。 + * 来源:独立 API 覆盖用例;含个人信息的 BugServer 来源已排除,不建立来源 ID 关联。 + */ +export default { + mount(container) { + // 用固定的通用字段和数值建立可观察的二维更新范围。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'id', title: 'ID', width: 100 }, + { field: 'amount', title: 'Amount', width: 120 }, + { field: 'state', title: 'State', width: 120 } + ], + records: [ + { id: 1, amount: 10, state: 'new' }, + { id: 2, amount: 20, state: 'new' }, + { id: 3, amount: 30, state: 'new' } + ] + }); + }, + async exercise(page) { + // 从第二列首条记录开始更新两行两列,并检查 API 的逐格成功结果。 + await page.evaluate(async () => { + const changed = await window.__visualTable.changeCellValues(1, 1, [[11, 'ready'], [21, 'hold']]); + if (changed.length !== 2 || changed.some(row => row.length !== 2 || row.some(value => value !== true))) + throw new Error('批量更新结果不完整'); + }); + }, + async verify(page) { + // 断言二维目标、原始记录和未触及的邻格均保持预期值。 + await page.evaluate(() => { + const table = window.__visualTable; + const expected = [[11, 'ready'], [21, 'hold']]; + for (let row = 0; row < expected.length; row++) { + for (let col = 0; col < expected[row].length; col++) { + if (table.getCellOriginValue(col + 1, row + 1) !== expected[row][col]) + throw new Error('批量更新的行列映射错误'); + } + } + if (table.getCellOriginValue(0, 1) !== 1 || table.getCellOriginValue(1, 3) !== 30) + throw new Error('批量更新越过目标范围'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index a9affb3ebe..19a80cc919 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -19,6 +19,11 @@ export const cases = [ { id: 'row-series-number', purpose: '独立行序号列', file: './header/row-series-number.mjs', bundles: ['vtable'] }, { id: 'scroll-bar-to-side', purpose: '滚动条贴边与多层表头', file: './scroll/bar-to-side.mjs', bundles: ['vtable'] }, { id: 'gantt-baseline-bottom', purpose: 'Gantt 基线与三级时间轴', file: './gantt/baseline-bottom.mjs', bundles: ['gantt'] }, + { id: 'select-highlight-row', purpose: '选择高亮 row', file: './interaction/select-highlight-row.mjs', bundles: ['vtable'] }, + { id: 'select-highlight-column', purpose: '选择高亮 column', file: './interaction/select-highlight-column.mjs', bundles: ['vtable'] }, + { id: 'select-highlight-cross-theme', purpose: '选择高亮 cross 主题', file: './interaction/select-highlight-cross-theme.mjs', bundles: ['vtable'] }, + { id: 'select-highlight-cross-header-cell', purpose: '选择高亮 cross 主题 表头单格', file: './interaction/select-highlight-cross-header-cell.mjs', bundles: ['vtable'] }, + { id: 'select-highlight-cross-transpose', purpose: '选择高亮 cross 主题 表头单格 转置', file: './interaction/select-highlight-cross-transpose.mjs', bundles: ['vtable'] }, { id: 'select-cross', purpose: 'cross 模式表体与表头连续选择', file: './interaction/select-cross.mjs', bundles: ['vtable'] }, { id: 'list-empty-resize', purpose: '空表在缩小视口中绘制', file: './empty/list-resize.mjs', bundles: ['vtable'] }, { id: 'edit-start-with-value', purpose: '输入编辑器启动初始值', file: './edit/start-with-value.mjs', bundles: ['editors'] }, @@ -53,6 +58,7 @@ export const cases = [ { id: 'style-dashed-border', purpose: '虚线双色单元格边框', file: './style/dashed-border.mjs', bundles: ['vtable'] }, { id: 'group-one-column', purpose: '隐藏分组字段的单列列表', file: './group/one-column.mjs', bundles: ['vtable'] }, { id: 'api-update-columns', purpose: '悬停时更新列', file: './api/update-columns.mjs', bundles: ['vtable'] }, + { id: 'api-change-cell-values', purpose: '二维批量更新单元格值', file: './api/change-cell-values.mjs', bundles: ['vtable'] }, { id: 'pivot-wide-scrollbar', purpose: '透视表宽滚动条与主题条纹', file: './scroll/pivot-wide-rail.mjs', bundles: ['vtable'] }, { id: 'edit-complete-input', purpose: '输入编辑器完成提交', file: './edit/complete-input.mjs', bundles: ['editors'] }, { id: 'select-disabled-column-range', purpose: '拖选不能覆盖禁选列', file: './interaction/disabled-column-range.mjs', bundles: ['vtable'] }, diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-column.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-column.mjs new file mode 100644 index 0000000000..2ec27ec881 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-column.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 665eb726faec2700ad74954d + * 验证目的:验证 column 选择高亮在表体和表头点击后的状态与截图。 + * 改写:使用固定匿名记录,按单元格矩形重放来源的点击顺序。 + */ +export default { + mount(container) { + // 构建该来源独有的选择配置与通用数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 10, id: 1, name: 'A' }, { progress: 20, id: 2, name: 'B' }, { progress: 30, id: 3, name: 'C' }], + select: { highlightMode: 'column' }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 重放来源的两次点击,先确认首个动作确实改变了选择,再保留最终状态截图。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(1, 2); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 2); + await click(1, 0); + }, + async verify(page) { + // 选择范围与高亮模式必须对应最终点击;截图检查主题和扩展着色。 + await page.evaluate(({ expectedScope, expectedRow, headerCell }) => { + const table = window.__visualTable; + const selected = table.getSelectedCellRanges()[0]; + if (table.stateManager.select.highlightScope !== expectedScope || !selected || selected.start.row !== expectedRow) + throw new Error('选择模式或最终位置错误'); + if (headerCell && expectedRow === 0 && (selected.start.col !== 1 || selected.end.col !== 1 || selected.end.row !== 0)) + throw new Error('表头没有保持单格选择'); + }, { expectedScope: 'column', expectedRow: 0, headerCell: false }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-header-cell.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-header-cell.mjs new file mode 100644 index 0000000000..40f7faf06c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-header-cell.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 665eba0ca4737f00b6623d44 + * 验证目的:验证 cross 选择高亮、自定义选择主题、表头单格选择在表体和表头点击后的状态与截图。 + * 改写:使用固定匿名记录,按单元格矩形重放来源的点击顺序。 + */ +export default { + mount(container) { + // 构建该来源独有的选择配置与通用数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 10, id: 1, name: 'A' }, { progress: 20, id: 2, name: 'B' }, { progress: 30, id: 3, name: 'C' }], + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff', inlineRowBgColor: '#ffe599', inlineColumnBgColor: '#d9e8ff' } }, + select: { highlightMode: 'cross', headerSelectMode: 'cell' }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 重放来源的两次点击,先确认首个动作确实改变了选择,再保留最终状态截图。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(1, 0); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 0); + await click(1, 2); + }, + async verify(page) { + // 选择范围与高亮模式必须对应最终点击;截图检查主题和扩展着色。 + await page.evaluate(({ expectedScope, expectedRow, headerCell }) => { + const table = window.__visualTable; + const selected = table.getSelectedCellRanges()[0]; + if (table.stateManager.select.highlightScope !== expectedScope || !selected || selected.start.row !== expectedRow) + throw new Error('选择模式或最终位置错误'); + if (headerCell && expectedRow === 0 && (selected.start.col !== 1 || selected.end.col !== 1 || selected.end.row !== 0)) + throw new Error('表头没有保持单格选择'); + }, { expectedScope: 'cross', expectedRow: 2, headerCell: true }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-theme.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-theme.mjs new file mode 100644 index 0000000000..3e8028e489 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-theme.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 665eb7fafaec2700ad749551 + * 验证目的:验证 cross 选择高亮、自定义选择主题在表体和表头点击后的状态与截图。 + * 改写:使用固定匿名记录,按单元格矩形重放来源的点击顺序。 + */ +export default { + mount(container) { + // 构建该来源独有的选择配置与通用数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 10, id: 1, name: 'A' }, { progress: 20, id: 2, name: 'B' }, { progress: 30, id: 3, name: 'C' }], + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff', inlineRowBgColor: '#ffe599', inlineColumnBgColor: '#d9e8ff' } }, + select: { highlightMode: 'cross' }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 重放来源的两次点击,先确认首个动作确实改变了选择,再保留最终状态截图。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(1, 2); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 2); + await click(1, 0); + }, + async verify(page) { + // 选择范围与高亮模式必须对应最终点击;截图检查主题和扩展着色。 + await page.evaluate(({ expectedScope, expectedRow, headerCell }) => { + const table = window.__visualTable; + const selected = table.getSelectedCellRanges()[0]; + if (table.stateManager.select.highlightScope !== expectedScope || !selected || selected.start.row !== expectedRow) + throw new Error('选择模式或最终位置错误'); + if (headerCell && expectedRow === 0 && (selected.start.col !== 1 || selected.end.col !== 1 || selected.end.row !== 0)) + throw new Error('表头没有保持单格选择'); + }, { expectedScope: 'cross', expectedRow: 0, headerCell: false }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-transpose.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-transpose.mjs new file mode 100644 index 0000000000..6e87ec71f7 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-cross-transpose.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 665ecceafaec2700ad749556 + * 验证目的:验证 cross 选择高亮、自定义选择主题、表头单格选择、转置布局在表体和表头点击后的状态与截图。 + * 改写:使用固定匿名记录,按单元格矩形重放来源的点击顺序。 + */ +export default { + mount(container) { + // 构建该来源独有的选择配置与通用数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 10, id: 1, name: 'A' }, { progress: 20, id: 2, name: 'B' }, { progress: 30, id: 3, name: 'C' }], + transpose: true, + theme: { selectionStyle: { cellBgColor: 'rgba(130, 178, 245, 0.2)', cellBorderLineWidth: 2, cellBorderColor: '#0000ff', inlineRowBgColor: '#ffe599', inlineColumnBgColor: '#d9e8ff' } }, + select: { highlightMode: 'cross', headerSelectMode: 'cell' }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 重放来源的两次点击,先确认首个动作确实改变了选择,再保留最终状态截图。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(1, 2); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 2); + await click(1, 0); + }, + async verify(page) { + // 选择范围与高亮模式必须对应最终点击;截图检查主题和扩展着色。 + await page.evaluate(({ expectedScope, expectedRow, headerCell }) => { + const table = window.__visualTable; + const selected = table.getSelectedCellRanges()[0]; + if (table.stateManager.select.highlightScope !== expectedScope || !selected || selected.start.row !== expectedRow) + throw new Error('选择模式或最终位置错误'); + if (headerCell && expectedRow === 0 && (selected.start.col !== 1 || selected.end.col !== 1 || selected.end.row !== 0)) + throw new Error('表头没有保持单格选择'); + }, { expectedScope: 'cross', expectedRow: 0, headerCell: true }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-row.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-row.mjs new file mode 100644 index 0000000000..e08d306c9c --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-row.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 665eb51cfaec2700ad74954a + * 验证目的:验证 row 选择高亮在表体和表头点击后的状态与截图。 + * 改写:使用固定匿名记录,按单元格矩形重放来源的点击顺序。 + */ +export default { + mount(container) { + // 构建该来源独有的选择配置与通用数据。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 100 }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 10, id: 1, name: 'A' }, { progress: 20, id: 2, name: 'B' }, { progress: 30, id: 3, name: 'C' }], + select: { highlightMode: 'row' }, + hover: { highlightMode: 'cross', disableHeaderHover: true } + }); + }, + async exercise(page) { + // 重放来源的两次点击,先确认首个动作确实改变了选择,再保留最终状态截图。 + const click = async (col, row) => { + const point = await page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + await page.mouse.click(point.x, point.y); + }; + await click(1, 2); + await page.waitForFunction(() => window.__visualTable.getSelectedCellRanges()[0]?.start.row === 2); + await click(1, 0); + }, + async verify(page) { + // 选择范围与高亮模式必须对应最终点击;截图检查主题和扩展着色。 + await page.evaluate(({ expectedScope, expectedRow, headerCell }) => { + const table = window.__visualTable; + const selected = table.getSelectedCellRanges()[0]; + if (table.stateManager.select.highlightScope !== expectedScope || !selected || selected.start.row !== expectedRow) + throw new Error('选择模式或最终位置错误'); + if (headerCell && expectedRow === 0 && (selected.start.col !== 1 || selected.end.col !== 1 || selected.end.row !== 0)) + throw new Error('表头没有保持单格选择'); + }, { expectedScope: 'row', expectedRow: 0, headerCell: false }); + } +}; From b9f06668409b8acdf4b95451ce1b1096279099b7 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 15:13:26 +0800 Subject: [PATCH 4/9] test: extend VTable visual cases and stabilize pie selection --- .github/workflows/vtable-visual.yml | 44 ------------- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 26 ++++---- .../vtable/__tests__/visual/cases/COVERAGE.md | 22 +++---- .../vtable/__tests__/visual/cases/index.mjs | 2 + .../interaction/drag-row-series-order.mjs | 54 +++++++++++++++ .../cases/pivot-chart/pie-multi-select.mjs | 14 ++-- .../cases/pivot/custom-sort-click-colors.mjs | 66 +++++++++++++++++++ 7 files changed, 155 insertions(+), 73 deletions(-) delete mode 100644 .github/workflows/vtable-visual.yml create mode 100644 packages/vtable/__tests__/visual/cases/interaction/drag-row-series-order.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/custom-sort-click-colors.mjs diff --git a/.github/workflows/vtable-visual.yml b/.github/workflows/vtable-visual.yml deleted file mode 100644 index d980d89a16..0000000000 --- a/.github/workflows/vtable-visual.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: VTable visual regression - -on: - pull_request: - branches: [develop] - paths: - - .github/workflows/vtable-visual.yml - - packages/vtable/** - - packages/vtable-editors/** - - packages/vtable-gantt/** - - packages/vtable-plugins/** - - packages/vtable-sheet/** - - tools/bundler/** - - common/config/rush/** - workflow_dispatch: - -permissions: - contents: read - -jobs: - visual: - runs-on: macos-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Install dependencies - run: node common/scripts/install-run-rush.js install --ignore-hooks - - name: Install Chromium - run: node packages/vtable/node_modules/@playwright/test/cli.js install chromium - - name: Check visual runner - run: node --test packages/vtable/scripts/visual-test.test.mjs - - name: Compare with official develop - run: node packages/vtable/scripts/visual-test.mjs - - name: Upload failure report - if: failure() - uses: actions/upload-artifact@v4 - with: - name: vtable-visual-report - path: .vtable-visual/runs/ - if-no-files-found: ignore - retention-days: 7 diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 4cece6c0d1..803a9c363e 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -5,12 +5,12 @@ "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, - "deferred_interaction": 160, + "deferred_interaction": 157, "deferred_large_source": 70, "deferred_resource": 31, "deferred_static": 216, - "migrated": 40, - "privacy_excluded": 10 + "migrated": 42, + "privacy_excluded": 11 }, "entries": [ { @@ -3251,9 +3251,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-custom-sort-click-colors", + "verification": "real sort-icon click + changed city order + two metric color mappings" }, { "id": "65817239eab07e0091708bb8", @@ -8029,9 +8030,10 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "drag-row-series-order", + "verification": "two row-series drags + record order + displayed order" }, { "id": "673c5c17013a5500b2fe99e0", @@ -9733,9 +9735,9 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains customer/order identifiers and product-level business records; source is excluded; no source-ID linkage to local cases" }, { "id": "68ff1d7f07d0a000a8414c50", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 160db0c9b5..9c7c180865 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,44 +1,44 @@ # 本地视觉用例覆盖 -本清单描述当前本地用例的实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +当前有 180 个本地用例,关联 202 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | | 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | | 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline`、`checkbox-header-options` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | | 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | -| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | +| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | | 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | | Sheet | `sheet-add-columns`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列插入、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | | 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | -| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | -| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、异步数据源配置更新时保留数据 | +| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | +| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | | 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 ## BugServer 未选候选去向(2026-09-24) -上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 40 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 42 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 40 | 33 个新模块,以匿名数据重建配置及动作 | -| 隐私风险排除 | 10 | 发现业务化字段或数值,原始内容没有进入仓库 | +| 已迁入本地用例 | 42 | 35 个新模块,以匿名数据重建配置及动作 | +| 隐私风险排除 | 11 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 160 | 录制动作缺少对应的本地动作与断言 | +| 交互未证明覆盖 | 157 | 录制动作缺少对应的本地动作与断言 | | 静态配置未证明覆盖 | 216 | 配置或数据变体缺少对应的本地断言 | -三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除,独立的 `api-change-cell-values` 用匿名固定记录验证二维更新,不关联这些来源 ID。 +三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有一条包含订单和客户标识的主从表来源排除。独立的 `api-change-cell-values` 用匿名固定记录验证二维更新,不关联被排除来源 ID。 新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 -继续补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,逐例保留真实来源 ID,验证表头/表体点击顺序与最终选择范围。 +继续补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。交互目录 16/16 与官方基线通过。 +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 180/180 与官方基线通过。 本轮新增可验证场景:列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index 19a80cc919..c85fd1e62f 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -54,6 +54,7 @@ export const cases = [ { id: 'hover-tooltip', purpose: '多单元格悬停提示更新', file: './components/hover-tooltip.mjs', bundles: ['vtable'] }, { id: 'menu-disabled-item', purpose: '下拉子菜单禁用项', file: './menu/disabled-item.mjs', bundles: ['vtable'] }, { id: 'pivot-indicator-sort-rule', purpose: '透视指标排序规则和背景映射', file: './pivot/indicator-sort-rule.mjs', bundles: ['vtable'] }, + { id: 'pivot-custom-sort-click-colors', purpose: '透视自定义比较器点击排序及双指标着色', file: './pivot/custom-sort-click-colors.mjs', bundles: ['vtable'] }, { id: 'key-size-config', purpose: '稳定 key 的列宽行高配置', file: './layout/key-size-config.mjs', bundles: ['vtable'] }, { id: 'style-dashed-border', purpose: '虚线双色单元格边框', file: './style/dashed-border.mjs', bundles: ['vtable'] }, { id: 'group-one-column', purpose: '隐藏分组字段的单列列表', file: './group/one-column.mjs', bundles: ['vtable'] }, @@ -139,6 +140,7 @@ export const cases = [ { id: 'gantt-tree-move-resize', purpose: '树形子任务条移动与拉伸', file: './gantt/tree-move-resize.mjs', bundles: ['gantt'] }, { id: 'group-add-delete-records', purpose: '两级分组内按路径增删记录', file: './group/add-delete-records.mjs', bundles: ['vtable'] }, { id: 'drag-row-series-select', purpose: '行序号列纵向拖选', file: './interaction/drag-row-series-select.mjs', bundles: ['vtable'] }, + { id: 'drag-row-series-order', purpose: '行序号两次拖动重排记录', file: './interaction/drag-row-series-order.mjs', bundles: ['vtable'] }, { id: 'keyboard-cut-paste-event', purpose: '事件剪贴板剪切两格并粘贴', file: './keyboard/cut-paste-event.mjs', bundles: ['vtable'] }, { id: 'pivot-empty-string-dimension', purpose: '透视空字符串列维度与普通列并存', file: './pivot/empty-string-dimension.mjs', bundles: ['vtable'] }, { id: 'pivot-chart-pie-multi-select', purpose: '透视饼图连续扇区多选', file: './pivot-chart/pie-multi-select.mjs', bundles: ['vchart'] }, diff --git a/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-order.mjs b/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-order.mjs new file mode 100644 index 0000000000..b1a6c08dfe --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/drag-row-series-order.mjs @@ -0,0 +1,54 @@ +/** + * BugServer case IDs: 673728e9013a5500b2fe99ca + * 验证目的:行序号拖动两次后,记录顺序与表体显示同步变化。 + * 改写:将来源的人员和邮箱记录换成固定编号,保留行号拖动与列头拖动配置。 + */ +export default { + mount(container) { + // 足够的匿名记录使两段录制拖动都落在可见表体内。 + container.style.height = '440px'; + return new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 120 }, { field: 'value', title: 'Value', width: 140 }], + records: Array.from({ length: 8 }, (_, index) => ({ id: index + 1, value: (index + 1) * 10 })), + dragHeaderMode: 'column', + rowSeriesNumber: { enable: true, title: 'No.', field: 'id', dragOrder: true, width: 60, style: { color: 'red' } } + }); + }, + async exercise(page) { + // 从行序号左侧拖动两段不同的行,并分别记录完成后的真实数据顺序。 + const drag = async (fromRow, toRow) => { + const points = await page.evaluate(({ fromRow, toRow }) => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + return [fromRow, toRow].map(row => { + const b = table.getCellRect(0, row).bounds; + return { x: host.x + b.x1 + 18, y: host.y + (b.y1 + b.y2) / 2 }; + }); + }, { fromRow, toRow }); + await page.mouse.move(points[0].x, points[0].y); + await page.mouse.down(); + await page.mouse.move(points[1].x, points[1].y, { steps: 15 }); + await page.mouse.up(); + }; + await drag(2, 5); + await page.evaluate(() => { + const order = window.__visualTable.records.map(record => record.id); + if (order.join(',') === '1,2,3,4,5,6,7,8') throw new Error('首次行序号拖动未重排'); + window.__afterFirstOrder = order.join(','); + }); + await drag(1, 4); + }, + async verify(page) { + // 两次拖动应分别改变顺序,同时保留全部记录且显示顺序跟随数据。 + await page.evaluate(() => { + const table = window.__visualTable; + const order = table.records.map(record => record.id); + if (order.join(',') === window.__afterFirstOrder || + order.slice().sort((a, b) => a - b).join(',') !== '1,2,3,4,5,6,7,8') + throw new Error('第二次拖动结果或记录集合错误'); + for (let row = 1; row <= order.length; row++) { + if (table.getCellOriginValue(1, row) !== order[row - 1]) throw new Error('显示顺序没有同步'); + } + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs index 8deaea1304..bd12821da2 100644 --- a/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/pie-multi-select.mjs @@ -34,19 +34,21 @@ export default { return table; }, async exercise(page) { - // 三次点击分别落在圆周不同象限,保留来源的连续选择动作。 + // 用图元数据求真实扇区坐标,避免图表在不同平台的单元格内偏移影响命中。 const points = await page.evaluate(() => { const table = window.__visualTable; const cell = Array.from({ length: table.rowCount }, (_, row) => Array.from({ length: table.colCount }, (_, col) => ({ col, row }))) .flat().find(({ col, row }) => table.getCellType(col, row) === 'chart'); if (!cell) throw new Error('饼图单元格未渲染'); - const b = table.getCellRect(cell.col, cell.row).bounds; + const paths = table.getCellHeaderPaths(cell.col, cell.row); const host = document.getElementById('table').getBoundingClientRect(); - const cx = host.x + (b.x1 + b.x2) / 2; - const cy = host.y + (b.y1 + b.y2) / 2; - return [{ x: cx + 70, y: cy }, { x: cx - 35, y: cy + 55 }, - { x: cx - 20, y: cy - 60 }]; + return [{ category: 'A', value: 6 }, { category: 'B', value: 9 }, { category: 'C', value: 12 }] + .map(datum => { + const position = table.getChartDatumPosition({ group: 'All', bucket: 'One', ...datum }, paths); + if (!position) throw new Error(`无法定位扇区 ${datum.category}`); + return { x: host.x + position.x, y: host.y + position.y }; + }); }); for (const point of points) await page.mouse.click(point.x, point.y); await page.mouse.move(650, 350); diff --git a/packages/vtable/__tests__/visual/cases/pivot/custom-sort-click-colors.mjs b/packages/vtable/__tests__/visual/cases/pivot/custom-sort-click-colors.mjs new file mode 100644 index 0000000000..f54c590725 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/custom-sort-click-colors.mjs @@ -0,0 +1,66 @@ +/** + * BugServer case IDs: 6581698ceab07e0091708bab + * 验证目的:透视行维度自定义比较器点击排序,同时两个指标采用独立背景映射。 + * 改写:地域与销售示例替换为固定 A/B/C 分类和整数,保留 sortFunc、双指标映射及点击动作。 + */ +export default { + mount(container) { + // 三个城市值故意不按名称排列,使初始排序和点击后的变化可观察。 + return new window.VTable.PivotTable(container, { + rows: [{ dimensionKey: 'region', title: 'Region' }, { dimensionKey: 'city', title: 'City', sort: true }], + columns: ['category', 'sub'], indicators: ['amount', 'count'], indicatorsAsCol: false, + enableDataAnalysis: true, corner: { titleOnDimension: 'row' }, + dataConfig: { + sortRules: [{ sortField: 'city', sortType: window.VTable.TYPES.SortType.ASC, + sortFunc: (a, b, type) => String(a).localeCompare(String(b)) * (type === 'DESC' ? -1 : 1) }], + mappingRules: [ + { bgColor: { indicatorKey: 'amount', mapping: ({ value }) => value >= 20 ? '#ffd6d6' : '#ffffff' } }, + { bgColor: { indicatorKey: 'count', mapping: ({ value }) => value >= 2 ? '#d6f5df' : '#ffffff' } } + ] + }, + records: [ + { region: 'R', city: 'B', category: 'X', sub: 'Y', amount: 20, count: 2 }, + { region: 'R', city: 'C', category: 'X', sub: 'Y', amount: 30, count: 3 }, + { region: 'R', city: 'A', category: 'X', sub: 'Y', amount: 10, count: 1 } + ] + }); + }, + async exercise(page) { + // 查找真实排序图标并点击一次,避免直接改状态掩盖交互问题。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const labels = Array.from({ length: table.rowCount }, (_, row) => table.getCellValue(1, row)); + window.__initialCityOrder = ['A', 'B', 'C'].map(value => labels.indexOf(value)).join(','); + const host = document.getElementById('table').getBoundingClientRect(); + for (let row = 0; row < table.rowCount; row++) { + for (let col = 0; col < table.colCount; col++) { + const stack = [table.scenegraph.getCell(col, row)]; + while (stack.length) { + const mark = stack.pop(); + if (mark?.attribute?.funcType === 'sort') { + const b = mark.globalAABBBounds; + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + } + stack.push(...(mark?.children ?? [])); + } + } + } + throw new Error('透视城市排序图标不存在'); + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 点击后城市行顺序必须变化,且两个指标值仍可读取,截图验证独立着色。 + await page.evaluate(() => { + const table = window.__visualTable; + const labels = Array.from({ length: table.rowCount }, (_, row) => table.getCellValue(1, row)); + const positions = ['A', 'B', 'C'].map(value => labels.indexOf(value)); + if (positions.some(index => index < 0) || positions.join(',') === window.__initialCityOrder) + throw new Error(`透视自定义排序未改变城市顺序:${labels}`); + if (!Array.from({ length: table.rowCount }, (_, row) => + Array.from({ length: table.colCount }, (_, col) => table.getCellValue(col, row))) + .flat().some(value => value === 30)) + throw new Error('排序后指标值丢失'); + }); + } +}; From 4a13e053ead4f7d611c98714df5cf041a9d9b92a Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 15:36:07 +0800 Subject: [PATCH 5/9] test: cover Sheet insertion boundaries in local visuals --- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 34 +++++++------ .../vtable/__tests__/visual/cases/COVERAGE.md | 16 +++---- .../vtable/__tests__/visual/cases/index.mjs | 4 ++ .../sheet/insert-columns-before-second.mjs | 48 +++++++++++++++++++ .../sheet/insert-columns-before-third.mjs | 48 +++++++++++++++++++ .../cases/sheet/insert-rows-after-first.mjs | 45 +++++++++++++++++ .../cases/sheet/insert-rows-at-start.mjs | 45 +++++++++++++++++ 7 files changed, 217 insertions(+), 23 deletions(-) create mode 100644 packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-second.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-third.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/insert-rows-after-first.mjs create mode 100644 packages/vtable/__tests__/visual/cases/sheet/insert-rows-at-start.mjs diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 803a9c363e..7df90354fe 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -1,15 +1,15 @@ { "product": "VTable", "sourceSnapshotDigest": "de03690e63b7859f62ae14d4efc521951a1ce71d9d5db33881bcf98c37b54d1c", - "officialBaselineSha": "464c0630f7123fff5b398229fa81680a75a96430", + "officialBaselineSha": "4e5ce4540dc5fb223360d5d7c08efdcfd56b3d78", "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, "deferred_interaction": 157, "deferred_large_source": 70, "deferred_resource": 31, - "deferred_static": 216, - "migrated": 42, + "deferred_static": 212, + "migrated": 46, "privacy_excluded": 11 }, "entries": [ @@ -9755,9 +9755,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "sheet-insert-columns-before-second", + "verification": "公式结果、列数和第二列前插入后的数值位置" }, { "id": "68ff1e7c479d9000abdefaf9", @@ -9775,9 +9776,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "sheet-insert-columns-before-third", + "verification": "公式结果、列数和第三列前插入后的数值位置" }, { "id": "68ff243743ec0700a96ec5b8", @@ -9795,9 +9797,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "sheet-insert-rows-at-start", + "verification": "公式结果、行数和首条记录前插入后的数值位置" }, { "id": "6915877abea5bb00a82e33e3", @@ -10518,9 +10521,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "sheet-insert-rows-after-first", + "verification": "公式结果、行数和第二条记录前插入后的数值位置" }, { "id": "69899af7657c7a005c098ad8", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 9c7c180865..06a455b0e1 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,6 +1,6 @@ # 本地视觉用例覆盖 -当前有 180 个本地用例,关联 202 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +当前有 184 个本地用例,关联 206 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | @@ -10,7 +10,7 @@ | 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | | 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | -| Sheet | `sheet-add-columns`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列插入、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | +| Sheet | `sheet-add-columns`、`sheet-insert-columns-before-second`、`sheet-insert-columns-before-third`、`sheet-insert-rows-at-start`、`sheet-insert-rows-after-first`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列与行的插入位置边界、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | | 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | | 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | | 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | @@ -20,26 +20,26 @@ Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移 ## BugServer 未选候选去向(2026-09-24) -上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 42 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 46 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 42 | 35 个新模块,以匿名数据重建配置及动作 | +| 已迁入本地用例 | 46 | 39 个新模块,以匿名数据重建配置及动作 | | 隐私风险排除 | 11 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | | 交互未证明覆盖 | 157 | 录制动作缺少对应的本地动作与断言 | -| 静态配置未证明覆盖 | 216 | 配置或数据变体缺少对应的本地断言 | +| 静态配置未证明覆盖 | 212 | 配置或数据变体缺少对应的本地断言 | 三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有一条包含订单和客户标识的主从表来源排除。独立的 `api-change-cell-values` 用匿名固定记录验证二维更新,不关联被排除来源 ID。 新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 -继续补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 +已补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 180/180 与官方基线通过。 +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 184/184 与官方基线通过。 -本轮新增可验证场景:列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 +本轮新增可验证场景:Sheet 在第二列和第三列前插列,以及首条和第二条记录前插行,已用实际数值位置断言;列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 这份台账是可继续处理的缺口清单,尚不能据此判断 BugServer 用例迁移已经完成。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index c85fd1e62f..6ed10dd877 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -64,6 +64,10 @@ export const cases = [ { id: 'edit-complete-input', purpose: '输入编辑器完成提交', file: './edit/complete-input.mjs', bundles: ['editors'] }, { id: 'select-disabled-column-range', purpose: '拖选不能覆盖禁选列', file: './interaction/disabled-column-range.mjs', bundles: ['vtable'] }, { id: 'sheet-add-rows', purpose: 'Sheet 行高调整与插入记录', file: './sheet/add-rows.mjs', bundles: ['sheet'] }, + { id: 'sheet-insert-columns-before-second', purpose: 'Sheet 第二列前插入两列', file: './sheet/insert-columns-before-second.mjs', bundles: ['sheet'] }, + { id: 'sheet-insert-columns-before-third', purpose: 'Sheet 第三列前插入两列', file: './sheet/insert-columns-before-third.mjs', bundles: ['sheet'] }, + { id: 'sheet-insert-rows-at-start', purpose: 'Sheet 第一条记录前插入两行', file: './sheet/insert-rows-at-start.mjs', bundles: ['sheet'] }, + { id: 'sheet-insert-rows-after-first', purpose: 'Sheet 第二条记录前插入两行', file: './sheet/insert-rows-after-first.mjs', bundles: ['sheet'] }, { id: 'pivot-no-indicators', purpose: '无指标透视表与链接型维度表头', file: './pivot/no-indicators.mjs', bundles: ['vtable'] }, { id: 'keyboard-select-all-body', purpose: '快捷键全选表体且排除表头', file: './keyboard/select-all-body.mjs', bundles: ['vtable'] }, { id: 'pivot-tree-zero-expand', purpose: '数字零值透视树节点展开', file: './pivot/tree-zero-expand.mjs', bundles: ['vtable'] }, diff --git a/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-second.mjs b/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-second.mjs new file mode 100644 index 0000000000..9ab30bca51 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-second.mjs @@ -0,0 +1,48 @@ +/** 为列与行插入边界用例创建相同的匿名 Sheet 初始矩阵。 */ +function createInsertSheet(container) { + container.style.height = '400px'; + return new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 200, columnCount: 10, + columns: [{ title: 'Values', width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], active: true }] + }); +} + +/** + * BugServer case IDs: 68ff1d7f07d0a000a8414c50 + * 验证目的:公式回填与两列宽调整后,在第二列前插入两列。 + * 改写:使用匿名数值矩阵,保留公式、列宽调整、插入位置及编辑动作。 + */ +export default { + mount(container) { + // 固定求和值使列插入前的公式结果可以直接校验。 + const sheet = createInsertSheet(container); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error || result.value !== 6) throw new Error(`SUM 结果错误:${JSON.stringify(result)}`); + const table = sheet.getActiveSheet().tableInstance; + table.changeCellValue(3, 4, result.value, false, false); + table.stateManager.startResizeCol(0, 230, 50); + table.stateManager.updateResizeCol(300, 50); + table.stateManager.endResizeCol(); + table.stateManager.startResizeCol(1, 230, 50); + table.stateManager.updateResizeCol(150, 50); + table.stateManager.endResizeCol(); + window.__insertColumnsBefore = table.colCount; + table.addColumns([{ field: 1 }, { field: 4 }], 1, true); + table.startEditCell(5, 4); + return sheet; + }, + async verify(page) { + // 新列必须位于原第二列前,原数值要保持顺序并向右移动两格。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (table.colCount !== window.__insertColumnsBefore + 2 || + table.getCellValue(0, 1) !== 1 || table.getCellValue(1, 1) !== undefined || + table.getCellValue(2, 1) !== undefined || table.getCellValue(3, 1) !== 2) + throw new Error('Sheet 第二列前插入位置或数值错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-third.mjs b/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-third.mjs new file mode 100644 index 0000000000..036ff3947b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/insert-columns-before-third.mjs @@ -0,0 +1,48 @@ +/** 为列与行插入边界用例创建相同的匿名 Sheet 初始矩阵。 */ +function createInsertSheet(container) { + container.style.height = '400px'; + return new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 200, columnCount: 10, + columns: [{ title: 'Values', width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], active: true }] + }); +} + +/** + * BugServer case IDs: 68ff1e7c479d9000abdefaf9 + * 验证目的:保留多区域公式配置,在第三列前插入两列且原数据右移。 + * 改写:使用匿名数值矩阵,保留列宽调整、插入位置及编辑动作。 + */ +export default { + mount(container) { + // 只设置公式,与来源一样不在插列前手动回填计算值。 + const sheet = createInsertSheet(container); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2,B3,C3)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error || result.value !== 17) throw new Error(`SUM 结果错误:${JSON.stringify(result)}`); + const table = sheet.getActiveSheet().tableInstance; + table.stateManager.startResizeCol(1, 230, 50); + table.stateManager.updateResizeCol(200, 50); + table.stateManager.endResizeCol(); + table.stateManager.startResizeCol(3, 230, 50); + table.stateManager.updateResizeCol(300, 50); + table.stateManager.endResizeCol(); + window.__insertColumnsBefore = table.colCount; + table.addColumns([{ field: 0 }, { field: 4 }], 2, true); + table.startEditCell(5, 4); + return sheet; + }, + async verify(page) { + // 原前两列不变,新增两列为空,原第三列位于第五列。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (table.colCount !== window.__insertColumnsBefore + 2 || + table.getCellValue(0, 1) !== 1 || table.getCellValue(1, 1) !== 2 || + table.getCellValue(2, 1) !== undefined || table.getCellValue(3, 1) !== undefined || + table.getCellValue(4, 1) !== 3) + throw new Error('Sheet 第三列前插入位置或数值错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/insert-rows-after-first.mjs b/packages/vtable/__tests__/visual/cases/sheet/insert-rows-after-first.mjs new file mode 100644 index 0000000000..33c9d29d54 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/insert-rows-after-first.mjs @@ -0,0 +1,45 @@ +/** 为列与行插入边界用例创建相同的匿名 Sheet 初始矩阵。 */ +function createInsertSheet(container) { + container.style.height = '400px'; + return new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 200, columnCount: 10, + columns: [{ title: 'Values', width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], active: true }] + }); +} + +/** + * BugServer case IDs: 6982e5a97a558400611ce04b + * 验证目的:公式回填与行高调整后,在第二条记录前插入两行。 + * 改写:使用匿名数值矩阵,保留插入位置与编辑动作。 + */ +export default { + mount(container) { + // 与首行插入用例分别启动工作表,验证不同的记录边界。 + const sheet = createInsertSheet(container); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2,B3,C3)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error || result.value !== 17) throw new Error(`SUM 结果错误:${JSON.stringify(result)}`); + const table = sheet.getActiveSheet().tableInstance; + table.changeCellValue(3, 4, result.value, false, false); + table.stateManager.startResizeRow(4, 230, 50); + table.stateManager.updateResizeRow(390, 80); + table.stateManager.endResizeRow(); + window.__insertRowsBefore = table.rowCount; + table.addRecords([[], []], 1, true); + table.startEditCell(3, 6); + return sheet; + }, + async verify(page) { + // 首条原记录保留在原位,第二条原记录下移两行。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (table.rowCount !== window.__insertRowsBefore + 2 || + table.getCellValue(0, 1) !== 1 || table.getCellValue(0, 2) !== undefined || + table.getCellValue(0, 3) !== undefined || table.getCellValue(0, 4) !== 4) + throw new Error('Sheet 第二行插入位置或数值错误'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/sheet/insert-rows-at-start.mjs b/packages/vtable/__tests__/visual/cases/sheet/insert-rows-at-start.mjs new file mode 100644 index 0000000000..e6038058ba --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/sheet/insert-rows-at-start.mjs @@ -0,0 +1,45 @@ +/** 为列与行插入边界用例创建相同的匿名 Sheet 初始矩阵。 */ +function createInsertSheet(container) { + container.style.height = '400px'; + return new window.VTableSheet.VTableSheet(container, { + showSheetTab: true, + sheets: [{ sheetKey: 'sheet1', sheetTitle: 'Sheet 1', rowCount: 200, columnCount: 10, + columns: [{ title: 'Values', width: 100 }], + data: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], active: true }] + }); +} + +/** + * BugServer case IDs: 68ff243743ec0700a96ec5b8 + * 验证目的:公式回填与行高调整后,在第一条记录前插入两行。 + * 改写:使用匿名数值矩阵,保留插入位置与编辑动作。 + */ +export default { + mount(container) { + // 固定多区域公式结果,随后复现首行插入前的行高调整。 + const sheet = createInsertSheet(container); + const cell = { sheet: 'sheet1', row: 4, col: 3 }; + sheet.formulaManager.setCellContent(cell, '=SUM(A2:C2,B3,C3)'); + const result = sheet.formulaManager.getCellValue(cell); + if (result.error || result.value !== 17) throw new Error(`SUM 结果错误:${JSON.stringify(result)}`); + const table = sheet.getActiveSheet().tableInstance; + table.changeCellValue(3, 4, result.value, false, false); + table.stateManager.startResizeRow(1, 230, 50); + table.stateManager.updateResizeRow(390, 80); + table.stateManager.endResizeRow(); + window.__insertRowsBefore = table.rowCount; + table.addRecords([[], []], 0, true); + table.startEditCell(3, 6); + return sheet; + }, + async verify(page) { + // 两行空记录位于最前,首条原记录的数值下移两行。 + await page.evaluate(() => { + const table = window.__visualTable.getActiveSheet().tableInstance; + if (table.rowCount !== window.__insertRowsBefore + 2 || + table.getCellValue(0, 1) !== undefined || table.getCellValue(0, 2) !== undefined || + table.getCellValue(0, 3) !== 1 || table.getCellValue(0, 4) !== 4) + throw new Error('Sheet 首行插入位置或数值错误'); + }); + } +}; From f0c47d65c2e40387012ad963a277d54f3ee95c28 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 15:50:28 +0800 Subject: [PATCH 6/9] test: cover anonymous Gantt header resize --- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 10 ++-- .../vtable/__tests__/visual/cases/COVERAGE.md | 12 ++-- .../cases/gantt/resize-task-list-header.mjs | 56 +++++++++++++++++++ .../vtable/__tests__/visual/cases/index.mjs | 1 + 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 packages/vtable/__tests__/visual/cases/gantt/resize-task-list-header.mjs diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 7df90354fe..313e5b8186 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -5,12 +5,12 @@ "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, - "deferred_interaction": 157, + "deferred_interaction": 156, "deferred_large_source": 70, "deferred_resource": 31, "deferred_static": 212, "migrated": 46, - "privacy_excluded": 11 + "privacy_excluded": 12 }, "entries": [ { @@ -9206,9 +9206,9 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business process information; source is not copied into the repository" }, { "id": "681c859484849700a73864dc", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 06a455b0e1..8f4cf55a42 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,6 +1,6 @@ # 本地视觉用例覆盖 -当前有 184 个本地用例,关联 206 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +当前有 185 个本地用例,关联 206 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | @@ -9,7 +9,7 @@ | 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | | 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | | 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | -| Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸 | +| Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize`、`gantt-resize-task-list-header` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸、任务列表列头拖动后双层时间轴布局 | | Sheet | `sheet-add-columns`、`sheet-insert-columns-before-second`、`sheet-insert-columns-before-third`、`sheet-insert-rows-at-start`、`sheet-insert-rows-after-first`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列与行的插入位置边界、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | | 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | | 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | @@ -25,20 +25,20 @@ Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移 | 去向 | 数量 | 含义 | | --- | ---: | --- | | 已迁入本地用例 | 46 | 39 个新模块,以匿名数据重建配置及动作 | -| 隐私风险排除 | 11 | 发现业务化字段或数值,原始内容没有进入仓库 | +| 隐私风险排除 | 12 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 157 | 录制动作缺少对应的本地动作与断言 | +| 交互未证明覆盖 | 156 | 录制动作缺少对应的本地动作与断言 | | 静态配置未证明覆盖 | 212 | 配置或数据变体缺少对应的本地断言 | -三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有一条包含订单和客户标识的主从表来源排除。独立的 `api-change-cell-values` 用匿名固定记录验证二维更新,不关联被排除来源 ID。 +三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有包含订单和客户标识的主从表来源、包含业务流程信息的 Gantt 来源排除。独立的 `api-change-cell-values` 与 `gantt-resize-task-list-header` 使用匿名固定数据,不关联被排除来源 ID。 新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 已补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 184/184 与官方基线通过。 +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 185/185 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 本轮新增可验证场景:Sheet 在第二列和第三列前插列,以及首条和第二条记录前插行,已用实际数值位置断言;列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 diff --git a/packages/vtable/__tests__/visual/cases/gantt/resize-task-list-header.mjs b/packages/vtable/__tests__/visual/cases/gantt/resize-task-list-header.mjs new file mode 100644 index 0000000000..5455dd8f37 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/gantt/resize-task-list-header.mjs @@ -0,0 +1,56 @@ +/** + * 验证目的:缩窄 Gantt 任务列表列头后,双层日期时间轴和任务条仍正常布局。 + * 独立匿名用例;不关联含业务流程信息的 BugServer 来源 ID。 + */ +export default { + mount(container) { + // 固定的匿名任务和日、小时双层刻度形成列头与日期表头的交界。 + container.style.height = '400px'; + return new window.VTableGantt.Gantt(container, { + records: [ + { id: 'a', title: 'Task A', start: '2025-01-02 09:00', end: '2025-01-02 15:00', checked: false }, + { id: 'b', title: 'Task B', start: '2025-01-03 08:00', end: '2025-01-03 12:00', checked: false } + ], + taskListTable: { + columns: [ + { field: 'checked', title: '', width: 50, cellType: 'checkbox', headerType: 'checkbox' }, + { field: 'title', title: 'Task', width: 220 }, + { field: 'start', title: 'Start', width: 160 } + ], + tableWidth: 'auto', frozenColCount: 1 + }, + frame: { verticalSplitLineMoveable: true }, + taskBar: { startDateField: 'start', endDateField: 'end', labelText: '{title}' }, + minDate: '2025-01-02 00:00', maxDate: '2025-01-04 00:00', + markLine: [{ date: '2025-01-02 13:30:00', style: { lineColor: 'red', lineWidth: 1 } }], + rowHeight: 40, headerRowHeight: 40, + timelineHeader: { colWidth: 40, scales: [{ unit: 'day', step: 1 }, { unit: 'hour', step: 1 }] } + }); + }, + async exercise(page) { + // 按真实列头右边界向左拖动约 60px,而非直接调用调整列宽 API。 + const point = await page.evaluate(() => { + const table = window.__visualTable.taskListTableInstance; + const bounds = table.getCellRect(1, 0).bounds; + const host = table.getContainer().getBoundingClientRect(); + window.__ganttColumnWidthBefore = table.getColWidth(1); + return { x: host.x + bounds.x2 - 1, y: host.y + (bounds.y1 + bounds.y2) / 2 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.down(); + await page.mouse.move(point.x - 60, point.y, { steps: 12 }); + await page.mouse.up(); + }, + async verify(page) { + // 列宽应确实缩小,时间轴与任务条仍可计算有效位置。 + await page.evaluate(() => { + const gantt = window.__visualTable; + const table = gantt.taskListTableInstance; + const width = table.getColWidth(1); + const timeX = gantt.getXByTime(new Date('2025-01-02T13:30:00').getTime()); + if (width > window.__ganttColumnWidthBefore - 30 || + !Number.isFinite(timeX) || !gantt.getTaskBarRelativeRect(0)) + throw new Error(`Gantt 列头缩窄后布局错误:${window.__ganttColumnWidthBefore} -> ${width}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index 6ed10dd877..c7d85ee62d 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -83,6 +83,7 @@ export const cases = [ { id: 'pivot-calculated-field-hidden-dependencies', purpose: '未显示依赖指标的计算字段', file: './pivot/calculated-field-hidden-dependencies.mjs', bundles: ['vtable'] }, { id: 'gantt-project-range-set-records', purpose: 'setRecords 项目时间边界重算', file: './gantt/project-range-set-records.mjs', bundles: ['gantt'] }, { id: 'gantt-empty-mark-line', purpose: '无任务的固定日期标记线', file: './gantt/empty-mark-line.mjs', bundles: ['gantt'] }, + { id: 'gantt-resize-task-list-header', purpose: 'Gantt 缩窄任务列表列头后双层时间轴保持布局', file: './gantt/resize-task-list-header.mjs', bundles: ['gantt'] }, { id: 'gantt-baseline-overlap', purpose: '基线与任务条重叠布局', file: './gantt/baseline-overlap.mjs', bundles: ['gantt'] }, { id: 'pivot-chart-heatmap-two-indicators', purpose: '双热力图数据流和颜色图例', file: './pivot-chart/heatmap-two-indicators.mjs', bundles: ['vchart'] }, { id: 'sheet-update-option', purpose: 'Sheet 全量配置更新', file: './sheet/update-option.mjs', bundles: ['sheet'] }, From 201d2e62767d8310bf51b60b4a460c5117a80191 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 16:40:44 +0800 Subject: [PATCH 7/9] test: expand VTable visual interaction coverage --- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 139 ++++++++++-------- .../vtable/__tests__/visual/cases/COVERAGE.md | 28 ++-- .../api/update-columns-after-selection.mjs | 43 ++++++ .../api/update-columns-on-mouseleave.mjs | 42 ++++++ .../cells/checkbox-over-thousand-rows.mjs | 48 ++++++ .../vtable/__tests__/visual/cases/index.mjs | 12 ++ .../interaction/disable-hover-columns.mjs | 43 ++++++ .../double-click-auto-column-width.mjs | 47 ++++++ .../double-click-auto-width-height.mjs | 44 ++++++ .../interaction/select-header-scroll-top.mjs | 41 ++++++ .../interaction/select-highlight-in-range.mjs | 44 ++++++ .../auto-fill-width-resize-container.mjs | 51 +++++++ .../pivot-chart/brush-multiple-selection.mjs | 71 +++++++++ .../pivot/update-sort-rules-after-click.mjs | 74 ++++++++++ .../auto-fill-grid-tree-origin-value.mjs | 59 ++++++++ 15 files changed, 710 insertions(+), 76 deletions(-) create mode 100644 packages/vtable/__tests__/visual/cases/api/update-columns-after-selection.mjs create mode 100644 packages/vtable/__tests__/visual/cases/api/update-columns-on-mouseleave.mjs create mode 100644 packages/vtable/__tests__/visual/cases/cells/checkbox-over-thousand-rows.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/disable-hover-columns.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/double-click-auto-column-width.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/double-click-auto-width-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-header-scroll-top.mjs create mode 100644 packages/vtable/__tests__/visual/cases/interaction/select-highlight-in-range.mjs create mode 100644 packages/vtable/__tests__/visual/cases/layout/auto-fill-width-resize-container.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/brush-multiple-selection.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/update-sort-rules-after-click.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/auto-fill-grid-tree-origin-value.mjs diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 313e5b8186..775cd94cec 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -5,12 +5,12 @@ "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", "counts": { "baseline_failure": 1, - "deferred_interaction": 156, + "deferred_interaction": 136, "deferred_large_source": 70, "deferred_resource": 31, "deferred_static": 212, - "migrated": 46, - "privacy_excluded": 12 + "migrated": 59, + "privacy_excluded": 19 }, "entries": [ { @@ -1769,9 +1769,10 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "layout-auto-fill-width-resize-container", + "verification": "dragged first-column width and remaining column after host resize" }, { "id": "653249d776bd2d82b5ce5e67", @@ -1899,9 +1900,10 @@ "click", "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "checkbox-over-thousand-rows", + "verification": "scroll beyond 1000 rows and checkbox state changes" }, { "id": "6540b514f95bdcf7c340d701", @@ -1924,9 +1926,10 @@ "drag", "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "layout-auto-fill-width-resize-container", + "verification": "stateManager resize, mouse drag and host width" }, { "id": "6540b960f95bdcf7c340d702", @@ -2224,9 +2227,10 @@ "click", "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "double-click-auto-column-width", + "verification": "mouse drag then double-click changes measured width" }, { "id": "6555f4339dabd71aa3845bb9", @@ -2245,9 +2249,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "double-click-auto-width-height", + "verification": "double-click changes width with auto row height" }, { "id": "6556050183c71200999f1f0c", @@ -2287,9 +2292,9 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "6559c76e38a83fc5d23015a1", @@ -2308,9 +2313,9 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "6559c7c838a83fc5d23015a4", @@ -3365,9 +3370,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "disable-hover-columns", + "verification": "hover.cellPos, disableHover and disableHeaderHover" }, { "id": "658c0a1b9f48b900833db069", @@ -4181,9 +4187,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "api-update-columns-after-selection", + "verification": "click callback, updated header and selected range" }, { "id": "65b2059f06085f008cf8f8f9", @@ -4359,9 +4366,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-update-sort-rules-after-click", + "verification": "pivot sort click and updated region order" }, { "id": "65c088a197cc3d008de5b484", @@ -4403,9 +4411,9 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "65c0983d97cc3d008de5b495", @@ -4426,9 +4434,9 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "65c09b2d97cc3d008de5b499", @@ -4506,9 +4514,10 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "api-update-columns-on-mouseleave", + "verification": "mouseleave callback, colCount and cell value" }, { "id": "65d4948797cc3d008de5b593", @@ -5384,9 +5393,9 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "662e20c6d4511700f6885626", @@ -7848,9 +7857,10 @@ "click", "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-highlight-in-range", + "verification": "selected range spans header and body with highlightInRange" }, { "id": "672c9d90e4bb4400b299cbd2", @@ -8207,9 +8217,9 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "675f9c36bb067d00b20cdcc1", @@ -9330,9 +9340,9 @@ "actionKinds": [ "move" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "privacy_excluded", + "priority": null, + "reason": "source contains business-like fields or values; source is not copied into the repository" }, { "id": "683ea8ae83f5b200a644bb88", @@ -10328,9 +10338,10 @@ "actionKinds": [ "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-chart-brush-multiple-selection", + "verification": "chart brush drag triggers brushEnd" }, { "id": "696739d9b71f44005d359b67", @@ -10597,9 +10608,10 @@ "click", "drag" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "plugin-auto-fill-grid-tree-origin-value", + "verification": "fill-handle drag and copy-fill changes target cell value" }, { "id": "6a1416f2709fdc006857f1dc", @@ -10622,9 +10634,10 @@ "actionKinds": [ "click" ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" + "status": "migrated", + "priority": null, + "localCase": "select-header-scroll-top", + "verification": "header selection and scrollTop after click" }, { "id": "6a68957b3dd664005e729649", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 8f4cf55a42..6357120855 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,35 +1,35 @@ # 本地视觉用例覆盖 -当前有 185 个本地用例,关联 206 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +当前有 197 个本地用例,关联 219 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | | 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | -| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline`、`checkbox-header-options` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | -| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | -| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | -| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | +| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline`、`checkbox-header-options`、`checkbox-over-thousand-rows` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | +| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen`、`layout-auto-fill-width-resize-container` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | +| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions`、`pivot-update-sort-rules-after-click` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | +| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover`、`pivot-chart-brush-multiple-selection` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize`、`gantt-resize-task-list-header` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸、任务列表列头拖动后双层时间轴布局 | | Sheet | `sheet-add-columns`、`sheet-insert-columns-before-second`、`sheet-insert-columns-before-third`、`sheet-insert-rows-at-start`、`sheet-insert-rows-after-first`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列与行的插入位置边界、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | -| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | -| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | -| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | +| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand`、`plugin-auto-fill-grid-tree-origin-value` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | +| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose`、`disable-hover-columns`、`select-highlight-in-range`、`select-header-scroll-top`、`double-click-auto-column-width`、`double-click-auto-width-height` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | +| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header`、`api-update-columns-on-mouseleave`、`api-update-columns-after-selection` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | | 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 ## BugServer 未选候选去向(2026-09-24) -上轮未选入的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 46 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +已审阅的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 59 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 46 | 39 个新模块,以匿名数据重建配置及动作 | -| 隐私风险排除 | 12 | 发现业务化字段或数值,原始内容没有进入仓库 | +| 已迁入本地用例 | 59 | 51 个新模块,以匿名数据重建配置及动作 | +| 隐私风险排除 | 19 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | | 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 156 | 录制动作缺少对应的本地动作与断言 | +| 交互未证明覆盖 | 136 | 录制动作缺少对应的本地动作与断言 | | 静态配置未证明覆盖 | 212 | 配置或数据变体缺少对应的本地断言 | 三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有包含订单和客户标识的主从表来源、包含业务流程信息的 Gantt 来源排除。独立的 `api-change-cell-values` 与 `gantt-resize-task-list-header` 使用匿名固定数据,不关联被排除来源 ID。 @@ -38,8 +38,10 @@ Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移 已补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 185/185 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 197/197 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 本轮新增可验证场景:Sheet 在第二列和第三列前插列,以及首条和第二条记录前插行,已用实际数值位置断言;列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 +本轮新增列级悬停禁用、跨表头选择、滚动后表头选择、鼠标事件回调更新列、拖动及双击列宽、插件填充柄复制、千行复选框、透视排序规则更新和透视图框选。另将 7 条含订单/客户标识或人员邮箱字段的来源标为隐私排除。 + 这份台账是可继续处理的缺口清单,尚不能据此判断 BugServer 用例迁移已经完成。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 diff --git a/packages/vtable/__tests__/visual/cases/api/update-columns-after-selection.mjs b/packages/vtable/__tests__/visual/cases/api/update-columns-after-selection.mjs new file mode 100644 index 0000000000..eda0b8f5b5 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/api/update-columns-after-selection.mjs @@ -0,0 +1,43 @@ +/** + * BugServer case IDs: 65af6e6906085f008cf8f85f + * 验证目的:点击选中单元格的回调内调用 updateColumns 后,选中状态与内容仍有效。 + * 改写:匿名固定记录保留点击触发更新的时机,用新标题使更新可观察。 + */ +export default { + mount(container) { + // 一次点击触发一次相同结构列的重新配置。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 110 }, { field: 'name', title: 'Name', width: 150 }], + records: [{ progress: 20, id: 1, name: 'A' }, { progress: 40, id: 2, name: 'B' }] + }); + window.__selectedColumnUpdates = 0; + table.on('click_cell', () => { + // 在点击事件同步调用 updateColumns,保留来源的重入路径。 + if (window.__selectedColumnUpdates++) return; + table.updateColumns([{ field: 'progress', title: 'Progress', width: 150 }, + { field: 'id', title: 'ID', width: 110 }, { field: 'name', title: 'Name updated', width: 150 }]); + }); + return table; + }, + async exercise(page) { + // 实际点击第二列数据格,不通过 selectCell API 注入选中状态。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(1, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + await page.waitForFunction(() => window.__selectedColumnUpdates > 0); + }, + async verify(page) { + // 点击时列结构重建完成,选中范围与新增标题同时保持。 + await page.evaluate(() => { + const table = window.__visualTable; + const range = table.getSelectedCellRanges()[0]; + if (window.__selectedColumnUpdates < 1 || table.colCount !== 3 || + table.getCellValue(2, 0) !== 'Name updated' || !range || range.start.col !== 1) + throw new Error(`点击更新后的选择状态异常:${JSON.stringify(range)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/api/update-columns-on-mouseleave.mjs b/packages/vtable/__tests__/visual/cases/api/update-columns-on-mouseleave.mjs new file mode 100644 index 0000000000..87d767fd52 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/api/update-columns-on-mouseleave.mjs @@ -0,0 +1,42 @@ +/** + * BugServer case IDs: 65d45c7a97cc3d008de5b576 + * 验证目的:鼠标离开单元格回调中更新列结构后表格继续正常绘制。 + * 改写:使用匿名记录,保留 mouseleave_cell 中 updateColumns 的调用时机。 + */ +export default { + mount(container) { + // 多行记录提供真实的单元格离开事件;回调只运行一次。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 110 }, + { field: 'name', title: 'Name', width: 180 }, { field: 'value', title: 'Value', width: 130 }], + records: [{ id: 1, name: 'A', value: 10 }, { id: 2, name: 'B', value: 20 }, + { id: 3, name: 'C', value: 30 }] + }); + window.__mouseleaveUpdates = 0; + table.on('mouseleave_cell', () => { + // 事件回调里重建列是本例要验证的路径。 + if (window.__mouseleaveUpdates++) return; + table.updateColumns([{ field: 'name', title: 'Name', width: 180 }]); + }); + return table; + }, + async exercise(page) { + // 从首个数据格移出到表格外侧,触发真实 mouseleave_cell。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(0, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.move(point.x, point.y); + await page.mouse.move(850, 550); + await page.waitForFunction(() => window.__mouseleaveUpdates > 0); + }, + async verify(page) { + // 更新后只保留 Name 列,原始记录仍可渲染。 + await page.evaluate(() => { + const table = window.__visualTable; + if (window.__mouseleaveUpdates < 1 || table.colCount !== 1 || table.getCellValue(0, 1) !== 'A') + throw new Error('鼠标离开后列更新失败'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/cells/checkbox-over-thousand-rows.mjs b/packages/vtable/__tests__/visual/cases/cells/checkbox-over-thousand-rows.mjs new file mode 100644 index 0000000000..1eacdeebf1 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/checkbox-over-thousand-rows.mjs @@ -0,0 +1,48 @@ +/** + * BugServer case IDs: 653b2f891053b2a37d5dc9b9 + * 验证目的:超过千行时滚动到远端后,冻结复选列仍可点击并保存状态。 + * 改写:重复固定匿名状态构建 2000 行,保留滚动和实际鼠标点击。 + */ +export default { + mount(container) { + // 五种复选状态重复 400 次,覆盖禁用、选中和未定义状态。 + const states = [ + { text: 'unchecked', checked: false, disable: false }, + { text: 'disabled', checked: false, disable: true }, + { text: 'checked', checked: true, disable: false }, + { text: 'locked', checked: true, disable: true }, + { text: 'unknown', disable: false } + ]; + const records = Array.from({ length: 2000 }, (_, index) => ({ + check: { ...states[index % states.length] }, name: `Item ${index + 1}` + })); + return new window.VTable.ListTable(container, { + columns: [{ field: '', title: 'All', headerType: 'checkbox', cellType: 'checkbox', width: 60 }, + { field: 'check', title: 'Check', headerType: 'checkbox', cellType: 'checkbox', width: 130 }, + { field: 'name', title: 'Name', width: 150 }], + records, defaultRowHeight: 32, frozenColCount: 2, allowFrozenColCount: 2 + }); + }, + async exercise(page) { + // 跳至第 1201 条记录并点击其未选中的冻结复选格。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + table.setScrollTop(1200 * 32); + const b = table.getCellRelativeRect(1, 1201).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__farCheckboxBefore = table.getCellCheckboxState(1, 1201); + return { x: host.x + b.x1 + 20, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 远端目标状态由 false 变 true,同时维持 2000 条记录。 + await page.evaluate(() => { + const table = window.__visualTable; + if (window.__farCheckboxBefore !== false || table.getCellCheckboxState(1, 1201) !== true || + table.rowCount !== 2001 || table.getScrollTop() < 30000) + throw new Error(`千行复选格更新失败:${JSON.stringify({ before: window.__farCheckboxBefore, + after: table.getCellCheckboxState(1, 1201), rows: table.rowCount, scrollTop: table.getScrollTop() })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index c7d85ee62d..bc9505b359 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -59,6 +59,18 @@ export const cases = [ { id: 'style-dashed-border', purpose: '虚线双色单元格边框', file: './style/dashed-border.mjs', bundles: ['vtable'] }, { id: 'group-one-column', purpose: '隐藏分组字段的单列列表', file: './group/one-column.mjs', bundles: ['vtable'] }, { id: 'api-update-columns', purpose: '悬停时更新列', file: './api/update-columns.mjs', bundles: ['vtable'] }, + { id: 'disable-hover-columns', purpose: '列级禁用表体和表头悬停', file: './interaction/disable-hover-columns.mjs', bundles: ['vtable'] }, + { id: 'select-highlight-in-range', purpose: '跨表头与表体拖选范围高亮', file: './interaction/select-highlight-in-range.mjs', bundles: ['vtable'] }, + { id: 'select-header-scroll-top', purpose: '滚动后固定表头仍可选择', file: './interaction/select-header-scroll-top.mjs', bundles: ['vtable'] }, + { id: 'api-update-columns-on-mouseleave', purpose: '鼠标离开单元格回调中更新列', file: './api/update-columns-on-mouseleave.mjs', bundles: ['vtable'] }, + { id: 'api-update-columns-after-selection', purpose: '点击选中时更新列并保持选区', file: './api/update-columns-after-selection.mjs', bundles: ['vtable'] }, + { id: 'layout-auto-fill-width-resize-container', purpose: '自动填宽下拖列边界和调整容器', file: './layout/auto-fill-width-resize-container.mjs', bundles: ['vtable'] }, + { id: 'double-click-auto-column-width', purpose: '拖宽后双击边界自动测量列宽', file: './interaction/double-click-auto-column-width.mjs', bundles: ['vtable'] }, + { id: 'double-click-auto-width-height', purpose: '自动行高换行时双击测量列宽', file: './interaction/double-click-auto-width-height.mjs', bundles: ['vtable'] }, + { id: 'plugin-auto-fill-grid-tree-origin-value', purpose: '树形表头填充柄拖动复制原值', file: './plugins/auto-fill-grid-tree-origin-value.mjs', bundles: ['plugins'] }, + { id: 'checkbox-over-thousand-rows', purpose: '千行外滚动与冻结复选格点击', file: './cells/checkbox-over-thousand-rows.mjs', bundles: ['vtable'] }, + { id: 'pivot-update-sort-rules-after-click', purpose: '透视排序图标点击后替换行列规则', file: './pivot/update-sort-rules-after-click.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-brush-multiple-selection', purpose: '双透视柱状图 multiple 框选拖动', file: './pivot-chart/brush-multiple-selection.mjs', bundles: ['vchart'] }, { id: 'api-change-cell-values', purpose: '二维批量更新单元格值', file: './api/change-cell-values.mjs', bundles: ['vtable'] }, { id: 'pivot-wide-scrollbar', purpose: '透视表宽滚动条与主题条纹', file: './scroll/pivot-wide-rail.mjs', bundles: ['vtable'] }, { id: 'edit-complete-input', purpose: '输入编辑器完成提交', file: './edit/complete-input.mjs', bundles: ['editors'] }, diff --git a/packages/vtable/__tests__/visual/cases/interaction/disable-hover-columns.mjs b/packages/vtable/__tests__/visual/cases/interaction/disable-hover-columns.mjs new file mode 100644 index 0000000000..1a064c386b --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/disable-hover-columns.mjs @@ -0,0 +1,43 @@ +/** + * BugServer case IDs: 6584086d807cf6008d99baad + * 验证目的:列级禁用表体和表头悬停,高亮仍可在普通列显示。 + * 改写:固定匿名记录,按实际单元格矩形重放两个录制的悬停动作。 + */ +export default { + mount(container) { + // 第一列禁用表体悬停,第二列禁用表头悬停,第三列作为正常对照。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'progress', title: 'Progress', width: 150, disableHover: true }, + { field: 'id', title: 'ID', width: 110, disableHeaderHover: true }, + { field: 'name', title: 'Name', width: 150 } + ], + records: [{ progress: 20, id: 1, name: 'A' }, { progress: 40, id: 2, name: 'B' }], + hover: { highlightMode: 'cross', disableHover: false }, + theme: { bodyStyle: { hover: { cellBgColor: '#B9D5FF' } }, + headerStyle: { hover: { cellBgColor: '#B9D5FF' } } } + }); + }, + async exercise(page) { + // 依次悬停普通列、禁用表头和禁用表体,最后保留禁用表体供截图比较。 + const point = (col, row) => page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + for (const [col, row] of [[2, 1], [1, 0], [0, 2]]) { + const p = await point(col, row); + await page.mouse.move(p.x, p.y); + } + }, + async verify(page) { + // 真实指针位置与两类列级禁用项同时成立,外观由截图比对。 + await page.evaluate(() => { + const table = window.__visualTable; + const hover = table.stateManager.hover; + if (hover.highlightScope !== 'cross' || hover.cellPos.col !== 0 || hover.cellPos.row !== 2 || + !table.getBodyColumnDefine(0, 2).disableHover || !table.getHeaderDefine(1, 0).disableHeaderHover) + throw new Error('列级悬停禁用场景无效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-column-width.mjs b/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-column-width.mjs new file mode 100644 index 0000000000..22f9242077 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-column-width.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6555e6399dabd71aa3845bb7 + * 验证目的:拖宽列后双击列边界,列宽按内容重新计算。 + * 改写:用匿名文本代替原始记录,按当前单元格边界计算鼠标位置。 + */ +export default { + mount(container) { + // 长文本列初始宽度固定为 150px,双击应自动测量其内容。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'a', title: 'A', width: 150 }, + { field: 'b', title: 'B', width: 100 }, + { field: 'description', title: 'Description', width: 150 }, + { field: 'name', title: 'Name', width: 150 }], + records: [{ a: 1, b: 2, description: 'A much longer description value', name: 'Item A' }, + { a: 3, b: 4, description: 'Short', name: 'Item B' }], + resize: { colResizeMode: 'all' } + }); + }, + async exercise(page) { + // 先把第三列拖宽,再双击其新的右侧边界。 + const edge = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(2, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + b.x2 - 1, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.move(edge.x, edge.y); + await page.mouse.down(); + await page.mouse.move(edge.x + 120, edge.y, { steps: 10 }); + await page.mouse.up(); + const resized = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(2, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__draggedColumnWidth = b.x2 - b.x1; + return { x: host.x + b.x2 - 1, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.dblclick(resized.x, resized.y, { delay: 80 }); + }, + async verify(page) { + // 拖动必须先增宽,双击后列宽应收缩至文本测量宽度。 + await page.evaluate(() => { + const b = window.__visualTable.getCellRect(2, 0).bounds; + const width = b.x2 - b.x1; + if (window.__draggedColumnWidth < 240 || width >= window.__draggedColumnWidth - 20 || width < 150) + throw new Error(`双击自动列宽未生效:${window.__draggedColumnWidth} -> ${width}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-width-height.mjs b/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-width-height.mjs new file mode 100644 index 0000000000..08c8f1a1cd --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/double-click-auto-width-height.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 6555f4339dabd71aa3845bb9 + * 验证目的:autoHeight 与自动换行同时启用时,双击列边界自动测量列宽并重排行高。 + * 改写:保留来源的列宽、自动换行和双击交互,记录换成匿名长文本。 + */ +export default { + mount(container) { + // 较长描述先换行,使列宽改变同时触发行高更新。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'a', title: 'A', width: 150 }, + { field: 'b', title: 'B', width: 100 }, + { field: 'description', title: 'Description', width: 150 }, + { field: 'name', title: 'Name', width: 150 }], + records: [{ a: 1, b: 2, + description: 'A much longer description value that should initially wrap into several lines', name: 'Item A' }, + { a: 3, b: 4, description: 'Short', name: 'Item B' }], + autoWrapText: true, heightMode: 'autoHeight', resize: { colResizeMode: 'all' } + }); + }, + async exercise(page) { + // 双击第三列表头边界,保留原来源的自动列宽操作。 + const edge = await page.evaluate(() => { + const table = window.__visualTable; + const b = table.getCellRect(2, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__autoWidthBefore = b.x2 - b.x1; + window.__autoRowHeightBefore = table.getCellRect(2, 1).bounds.y2 - table.getCellRect(2, 1).bounds.y1; + return { x: host.x + b.x2 - 1, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.dblclick(edge.x, edge.y, { delay: 80 }); + }, + async verify(page) { + // 文本自动测量后列宽改变,且自动行高未小于最小行高。 + await page.evaluate(() => { + const table = window.__visualTable; + const col = table.getCellRect(2, 0).bounds; + const row = table.getCellRect(2, 1).bounds; + const width = col.x2 - col.x1; + const height = row.y2 - row.y1; + if (width <= window.__autoWidthBefore || height < 24 || height > window.__autoRowHeightBefore + 2) + throw new Error(`双击列宽和自动行高异常:${JSON.stringify({ width, height })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-header-scroll-top.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-header-scroll-top.mjs new file mode 100644 index 0000000000..cf9b45ce18 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-header-scroll-top.mjs @@ -0,0 +1,41 @@ +/** + * BugServer case IDs: 6a1416f2709fdc006857f1dc + * 验证目的:大量记录滚动后,冻结表头选择仍位于表头且滚动位置不回跳。 + * 改写:使用匿名序号记录,保留冻结行、inline 表头选择和滚动动作。 + */ +export default { + mount(container) { + // 足够多的记录使 1000px 纵向滚动始终有真实表体可绘制。 + container.style.height = '400px'; + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'name', title: 'Name', width: 180 }, + { field: 'value', title: 'Value', width: 140 }, { field: 'group', title: 'Group', width: 140 }], + records: Array.from({ length: 120 }, (_, i) => ({ name: `Item ${i + 1}`, value: i, group: `G${i % 4}` })), + frozenRowCount: 5, heightMode: 'standard', widthMode: 'standard', + select: { headerSelectMode: 'inline', highlightMode: 'column' } + }); + table.selectCell(2, 0); + table.setScrollTop(1000); + return table; + }, + async exercise(page) { + // 在已滚动状态下点击同一列的固定表头。 + const point = await page.evaluate(() => { + const b = window.__visualTable.getCellRect(2, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__scrollBeforeHeaderClick = window.__visualTable.getScrollTop(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(point.x, point.y); + }, + async verify(page) { + // 表头仍被选中且滚动位置保持在原区域。 + await page.evaluate(() => { + const table = window.__visualTable; + const range = table.getSelectedCellRanges()[0]; + if (window.__scrollBeforeHeaderClick < 500 || table.getScrollTop() < 500 || + !range || range.start.row !== 0 || range.start.col !== 2) + throw new Error(`滚动后的表头选择异常:${JSON.stringify(range)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/interaction/select-highlight-in-range.mjs b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-in-range.mjs new file mode 100644 index 0000000000..4376ac6813 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/interaction/select-highlight-in-range.mjs @@ -0,0 +1,44 @@ +/** + * BugServer case IDs: 672b5b0b71189400b2ec8d56 + * 验证目的:跨行列拖选时 highlightInRange 在范围内着色,表头仍可参与选择。 + * 改写:用匿名三列记录和单元格位置代替固定录制坐标。 + */ +export default { + mount(container) { + // 保留 cross 高亮与表头 inline 选择,使用固定短记录。 + return new window.VTable.ListTable(container, { + columns: [{ field: 'a', title: 'A', width: 130 }, + { field: 'b', title: 'B', width: 130 }, { field: 'c', title: 'C', width: 130 }], + records: [{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, + { a: 7, b: 8, c: 9 }, { a: 10, b: 11, c: 12 }], + select: { headerSelectMode: 'inline', highlightMode: 'cross', highlightInRange: true } + }); + }, + async exercise(page) { + // 先在表体拖选,再点表头,最终从表头拖到表体留下跨边界范围。 + const point = (col, row) => page.evaluate(({ col, row }) => { + const b = window.__visualTable.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + (b.x1 + b.x2) / 2, y: host.y + (b.y1 + b.y2) / 2 }; + }, { col, row }); + const drag = async (a, b) => { + await page.mouse.move(a.x, a.y); + await page.mouse.down(); + await page.mouse.move(b.x, b.y, { steps: 8 }); + await page.mouse.up(); + }; + await drag(await point(0, 1), await point(1, 2)); + await page.mouse.click(...Object.values(await point(0, 0))); + await drag(await point(0, 0), await point(2, 3)); + }, + async verify(page) { + // 最终范围必须跨越表头和表体,且高亮范围配置保持启用。 + await page.evaluate(() => { + const table = window.__visualTable; + const range = table.getSelectedCellRanges()[0]; + if (!table.stateManager.select.highlightInRange || !range || + range.start.row !== 0 || range.end.row < 3 || range.end.col < 2) + throw new Error(`跨表头选择范围错误:${JSON.stringify(range)}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/layout/auto-fill-width-resize-container.mjs b/packages/vtable/__tests__/visual/cases/layout/auto-fill-width-resize-container.mjs new file mode 100644 index 0000000000..e802a57dcc --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/layout/auto-fill-width-resize-container.mjs @@ -0,0 +1,51 @@ +/** + * BugServer case IDs: 6532320388cd1012fefa741c, 6540b514f95bdcf7c340d701 + * 验证目的:autoFillWidth 下拖动列边界,再改变容器宽度,列宽与表格仍同步更新。 + * 改写:合并同配置的两条来源,保留内部初始调整、真实鼠标拖动和容器变化。 + */ +export default { + mount(container) { + // 固定两列和容器宽度,先按来源通过状态管理器调整首列。 + container.style.width = '800px'; + container.style.height = '400px'; + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'progress', title: 'Progress', showSort: true }, + { field: 'id', title: 'ID', width: 100 }], + records: [{ progress: 100, id: 1 }, { progress: 80, id: 2 }, + { progress: 60, id: 3 }, { progress: 40, id: 4 }], + autoFillWidth: true, widthMode: 'standard', allowFrozenColCount: 2, + resize: { colResizeMode: 'all' } + }); + table.stateManager.startResizeCol(0, 700, 120); + table.stateManager.updateResizeCol(670, 120); + table.stateManager.endResizeCol(); + return table; + }, + async exercise(page) { + // 从首列表头右边界向左拖动,再将宿主增宽 1px 触发重新布局。 + const edge = await page.evaluate(() => { + const table = window.__visualTable; + const b = table.getCellRect(0, 0).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + window.__widthBeforeDrag = b.x2 - b.x1; + return { x: host.x + b.x2 - 1, y: host.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.move(edge.x, edge.y); + await page.mouse.down(); + await page.mouse.move(edge.x - 100, edge.y, { steps: 10 }); + await page.mouse.up(); + await page.evaluate(() => { document.getElementById('table').style.width = '801px'; }); + await page.waitForTimeout(100); + }, + async verify(page) { + // 最终首列必须比拖动前窄,容器变化后其余列仍有有效宽度。 + await page.evaluate(() => { + const table = window.__visualTable; + const first = table.getCellRect(0, 0).bounds; + const last = table.getCellRect(1, 0).bounds; + if (first.x2 - first.x1 >= window.__widthBeforeDrag - 30 || last.x2 - last.x1 < 80 || + document.getElementById('table').clientWidth !== 801) + throw new Error(`容器变化后列宽异常:${JSON.stringify({ before: window.__widthBeforeDrag, first, last })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/brush-multiple-selection.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/brush-multiple-selection.mjs new file mode 100644 index 0000000000..6e075d03a9 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/brush-multiple-selection.mjs @@ -0,0 +1,71 @@ +/** + * BugServer case IDs: 6954de338ff7e3005dfc6526 + * 验证目的:透视柱状图启用 multiple x 轴框选时,拖动触发 brushEnd 并保留选区。 + * 改写:用三个匿名维度和本地 VChart 构建最小图表,保留实际鼠标拖动。 + */ +export default { + mount(container) { + // 本地图表模块使用两个共享维度指标,两个图表均开启 multiple 框选。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + container.style.width = '760px'; + container.style.height = '380px'; + window.__brushEndCount = 0; + // 为两个指标创建相同的横向多次框选配置。 + const chartSpec = (id, field) => ({ + type: 'bar', direction: 'vertical', data: { id }, + xField: 'category', yField: field, + brush: { visible: true, brushType: 'x', brushMode: 'multiple', + inBrush: { colorAlpha: 1 }, outOfBrush: { colorAlpha: 0.2 } }, + animation: false + }); + const table = new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['bucket'], indicatorsAsCol: false, + indicators: [ + { indicatorKey: 'amount', title: 'Amount', cellType: 'chart', chartModule: 'vchart', + chartSpec: chartSpec('amount', 'amount') }, + { indicatorKey: 'count', title: 'Count', cellType: 'chart', chartModule: 'vchart', + chartSpec: chartSpec('count', 'count') } + ], + records: [ + { group: 'All', bucket: 'One', category: 'A', amount: 10, count: 4 }, + { group: 'All', bucket: 'One', category: 'B', amount: 16, count: 8 }, + { group: 'All', bucket: 'One', category: 'C', amount: 12, count: 5 } + ], + defaultRowHeight: 250, defaultColWidth: 500, + defaultHeaderRowHeight: 30, defaultHeaderColWidth: 80, + chartDimensionLinkage: {} + }); + table.onVChartEvent('brushEnd', () => { window.__brushEndCount++; }); + return table; + }, + async exercise(page) { + // 在首个可见图表单元格的绘图区水平拖动创建框选。 + const segment = await page.evaluate(() => { + const table = window.__visualTable; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') { + const b = table.getCellRect(col, row).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { start: { x: host.x + b.x1 + 100, + y: host.y + (b.y1 + b.y2) / 2 }, + end: { x: host.x + b.x1 + 360, + y: host.y + (b.y1 + b.y2) / 2 } }; + } + throw new Error('框选图表单元格缺失'); + }); + await page.mouse.move(segment.start.x - 15, segment.start.y); + await page.mouse.move(segment.start.x, segment.start.y, { steps: 5 }); + await page.waitForTimeout(150); + await page.mouse.down(); + await page.mouse.move(segment.end.x, segment.end.y, { steps: 12 }); + await page.mouse.up(); + await page.waitForTimeout(150); + }, + async verify(page) { + // 至少一个图表收到 brushEnd,证明录制的拖动进入了 VChart 框选路径。 + await page.evaluate(() => { + if (window.__brushEndCount < 1) throw new Error('透视图未触发框选结束事件'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/update-sort-rules-after-click.mjs b/packages/vtable/__tests__/visual/cases/pivot/update-sort-rules-after-click.mjs new file mode 100644 index 0000000000..fc9b48b118 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/update-sort-rules-after-click.mjs @@ -0,0 +1,74 @@ +/** + * BugServer case IDs: 65be113cce3320008eecf686 + * 验证目的:透视排序图标点击后,updateSortRules 同时替换行维度和列维度规则。 + * 改写:地域和品类均换成匿名维度,保留双指标、层级、总计及规则更新。 + */ +export default { + mount(container) { + // 初始按 Amount 降序排列区域;三条记录使更新为升序后顺序可见。 + const table = new window.VTable.PivotTable(container, { + rows: [{ dimensionKey: 'region', title: 'Region', sort: true }, + { dimensionKey: 'city', title: 'City', sort: true }], + columns: ['category', { dimensionKey: 'variant', title: 'Variant', sort: true }], + indicators: ['amount', 'count'], indicatorsAsCol: true, + enableDataAnalysis: true, corner: { titleOnDimension: 'all' }, + dataConfig: { + sortRules: [{ sortField: 'region', sortByIndicator: 'amount', + sortType: window.VTable.TYPES.SortType.DESC, query: ['X', 'X1'] }], + totals: { row: { subTotalsDimensions: ['region'] } } + }, + records: [ + { region: 'R1', city: 'A', category: 'X', variant: 'X1', amount: 30, count: 3 }, + { region: 'R1', city: 'B', category: 'X', variant: 'X1', amount: 20, count: 2 }, + { region: 'R2', city: 'C', category: 'X', variant: 'X1', amount: 5, count: 1 }, + { region: 'R1', city: 'A', category: 'X', variant: 'X2', amount: 40, count: 4 }, + { region: 'R2', city: 'C', category: 'X', variant: 'X2', amount: 10, count: 2 } + ], widthMode: 'autoWidth' + }); + window.__pivotSortClicks = 0; + table.on('pivot_sort_click', () => { window.__pivotSortClicks++; }); + return table; + }, + async exercise(page) { + // 点击真实透视排序图标后再通过公开 API 替换两条规则。 + const point = await page.evaluate(() => { + const table = window.__visualTable; + const host = document.getElementById('table').getBoundingClientRect(); + for (let row = 0; row < table.rowCount; row++) { + for (let col = 0; col < table.colCount; col++) { + const stack = [table.scenegraph.getCell(col, row)]; + while (stack.length) { + const mark = stack.pop(); + if (mark?.attribute?.funcType === 'sort') { + const b = mark.globalAABBBounds; + return { x: host.x + (b.x1 + b.x2) / 2, + y: host.y + (b.y1 + b.y2) / 2 }; + } + stack.push(...(mark?.children ?? [])); + } + } + } + throw new Error('透视排序图标缺失'); + }); + await page.mouse.click(point.x, point.y); + await page.evaluate(() => { + window.__visualTable.updateSortRules([ + { sortField: 'region', sortByIndicator: 'amount', + sortType: window.VTable.TYPES.SortType.ASC, query: ['X', 'X1'] }, + { sortField: 'variant', sortByIndicator: 'amount', + sortType: window.VTable.TYPES.SortType.DESC, query: ['R1', 'A'] } + ]); + }); + }, + async verify(page) { + // 升序后较小值区域 R2 必须早于 R1,并且点击事件已触发。 + await page.evaluate(() => { + const table = window.__visualTable; + const labels = Array.from({ length: table.rowCount }, (_, row) => table.getCellValue(0, row)); + const r2 = labels.indexOf('R2'); + const r1 = labels.indexOf('R1'); + if (window.__pivotSortClicks < 1 || r2 < 0 || r1 < 0 || r2 >= r1) + throw new Error(`透视排序规则未更新:${JSON.stringify({ clicks: window.__pivotSortClicks, labels })}`); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/auto-fill-grid-tree-origin-value.mjs b/packages/vtable/__tests__/visual/cases/plugins/auto-fill-grid-tree-origin-value.mjs new file mode 100644 index 0000000000..c6050459a8 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/auto-fill-grid-tree-origin-value.mjs @@ -0,0 +1,59 @@ +/** + * BugServer case IDs: 69d614f2e41b43005d89a624 + * 验证目的:grid-tree 表头下拖动填充柄,插件将原单元格值复制到目标行。 + * 改写:用三条匿名记录重建树形表头,保留真实拖动和填充菜单选择。 + */ +export default { + mount(container) { + // 由 AutoFillPlugin 处理填充柄拖动,首列源格为固定文本 Seed。 + const table = new window.VTable.ListTable(container, { + columns: [{ field: 'id', title: 'ID', width: 100 }, + { title: 'Group', columns: [{ field: 'name', title: 'Name', width: 150 }, + { field: 'value', title: 'Value', width: 150 }] }], + records: [{ id: 1, name: 'Seed', value: 10 }, + { id: 2, name: 'Other', value: 20 }, { id: 3, name: 'Third', value: 30 }], + headerHierarchyType: 'grid-tree', headerExpandLevel: 2, + excelOptions: { fillHandle: true }, + plugins: [new window.VTable.plugins.AutoFillPlugin()] + }); + return table; + }, + async exercise(page) { + // 先选中源值,再从实际填充柄拖至下一行并选择复制填充。 + const source = await page.evaluate(() => { + const table = window.__visualTable; + const row = table.columnHeaderLevelCount; + const b = table.scenegraph.getCell(1, row).globalAABBBounds; + const canvas = table.canvas.getBoundingClientRect(); + return { x: canvas.x + (b.x1 + b.x2) / 2, + y: canvas.y + (b.y1 + b.y2) / 2 }; + }); + await page.mouse.click(source.x, source.y); + const points = await page.evaluate(() => { + const table = window.__visualTable; + const row = table.columnHeaderLevelCount; + const handle = [...table.scenegraph.selectedRangeComponents.values()][0]?.fillhandle?.globalAABBBounds; + if (!handle) throw new Error('列表填充柄未显示'); + const target = table.scenegraph.getCell(1, row + 1).globalAABBBounds; + const canvas = table.canvas.getBoundingClientRect(); + return { start: { x: canvas.x + (handle.x1 + handle.x2) / 2, + y: canvas.y + (handle.y1 + handle.y2) / 2 }, + end: { x: canvas.x + target.x2 - 8, y: canvas.y + target.y2 - 8 } }; + }); + await page.mouse.move(points.start.x, points.start.y); + await page.mouse.down(); + await page.mouse.move(points.end.x, points.end.y, { steps: 10 }); + await page.mouse.up(); + await page.locator('.vtable__menu-element__item').filter({ hasText: '复制填充' }).click(); + }, + async verify(page) { + // 目标行必须由 Other 变为 Seed,源行和下一行保持各自值。 + await page.evaluate(() => { + const table = window.__visualTable; + const row = table.columnHeaderLevelCount; + const values = [row, row + 1, row + 2].map(r => table.getCellValue(1, r)); + if (values[0] !== 'Seed' || values[1] !== 'Seed' || values[2] !== 'Third') + throw new Error(`列表复制填充结果错误:${values}`); + }); + } +}; From 357865298ea0414a3bda9340c8c9bc030080a7bf Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 17:43:43 +0800 Subject: [PATCH 8/9] test: cover remaining representative BugServer visual gaps --- .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 62 +++++++++++-------- .../vtable/__tests__/visual/cases/COVERAGE.md | 22 +++---- .../cases/cells/link-merged-auto-height.mjs | 47 ++++++++++++++ .../vtable/__tests__/visual/cases/index.mjs | 7 +++ .../cases/pivot-chart/area-axis-sort.mjs | 38 ++++++++++++ .../pivot-chart/rose-indicator-title.mjs | 40 ++++++++++++ .../cases/pivot/chart-spec-mark-line.mjs | 40 ++++++++++++ .../visual/cases/pivot/color-legend-order.mjs | 35 +++++++++++ .../cases/pivot/indicator-hide-frozen.mjs | 45 ++++++++++++++ .../cases/plugins/excel-delete-range.mjs | 46 ++++++++++++++ 10 files changed, 344 insertions(+), 38 deletions(-) create mode 100644 packages/vtable/__tests__/visual/cases/cells/link-merged-auto-height.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/area-axis-sort.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot-chart/rose-indicator-title.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/chart-spec-mark-line.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/color-legend-order.mjs create mode 100644 packages/vtable/__tests__/visual/cases/pivot/indicator-hide-frozen.mjs create mode 100644 packages/vtable/__tests__/visual/cases/plugins/excel-delete-range.mjs diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json index 775cd94cec..ab393102c0 100644 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json @@ -6,10 +6,10 @@ "counts": { "baseline_failure": 1, "deferred_interaction": 136, - "deferred_large_source": 70, + "deferred_large_source": 68, "deferred_resource": 31, - "deferred_static": 212, - "migrated": 59, + "deferred_static": 206, + "migrated": 67, "privacy_excluded": 19 }, "entries": [ @@ -1972,9 +1972,10 @@ "click", "move" ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + "status": "migrated", + "priority": null, + "localCase": "pivot-chart-area-axis-sort", + "verification": "area chart cell and rendered screenshot" }, { "id": "6541ecf501e33ad70dc01e38", @@ -2014,9 +2015,10 @@ "methodSignals": [], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-indicator-hide-frozen", + "verification": "right and bottom frozen counts" }, { "id": "654348a6b3dae69746d08701", @@ -4565,9 +4567,10 @@ "line" ], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-chart-spec-mark-line", + "verification": "chartSpec callback and two chart cells" }, { "id": "65d59c5d97cc3d008de5b5a7", @@ -8278,9 +8281,10 @@ "methodSignals": [], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-indicator-hide-frozen", + "verification": "hidden indicator values and callback paths" }, { "id": "676bb773df600200b24f54db", @@ -10093,9 +10097,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "plugin-excel-delete-range", + "verification": "Delete clears selected editable range only" }, { "id": "692d599f94f4f800664fe7a5", @@ -10317,9 +10322,10 @@ "rose" ], "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" + "status": "migrated", + "priority": null, + "localCase": "pivot-chart-rose-indicator-title", + "verification": "rose chart cell and rendered screenshot" }, { "id": "6954de338ff7e3005dfc6526", @@ -10466,9 +10472,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "pivot-color-legend-order", + "verification": "visible legend bounds and top layout" }, { "id": "697f0e81cfeff4005eb02fa4", @@ -10764,9 +10771,10 @@ ], "chartTypes": [], "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" + "status": "migrated", + "priority": null, + "localCase": "link-merged-auto-height", + "verification": "link type, merged range, no navigation" }, { "id": "6a8c044f1d0efd005e397e9f", diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 6357120855..719b206499 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,17 +1,17 @@ # 本地视觉用例覆盖 -当前有 197 个本地用例,关联 219 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +当前有 204 个本地用例,关联 227 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 | 功能 | 当前代表用例 | 主要条件 | | --- | --- | --- | | 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | -| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`style-underline`、`checkbox-header-options`、`checkbox-over-thousand-rows` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、下划线 | +| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`link-merged-auto-height`、`style-underline`、`checkbox-header-options`、`checkbox-over-thousand-rows` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、合并链接及禁用跳转、下划线 | | 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen`、`layout-auto-fill-width-resize-container` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | -| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions`、`pivot-update-sort-rules-after-click` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标 | -| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover`、`pivot-chart-brush-multiple-selection` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示 | +| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions`、`pivot-update-sort-rules-after-click`、`pivot-indicator-hide-frozen`、`pivot-color-legend-order`、`pivot-chart-spec-mark-line` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标、按维度隐藏指标、右列与底行冻结、顶部图例布局、单元格图表标记线 | +| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover`、`pivot-chart-brush-multiple-selection`、`pivot-chart-area-axis-sort`、`pivot-chart-rose-indicator-title` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示、面积图、玫瑰图与指标标题 | | Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize`、`gantt-resize-task-list-header` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸、任务列表列头拖动后双层时间轴布局 | | Sheet | `sheet-add-columns`、`sheet-insert-columns-before-second`、`sheet-insert-columns-before-third`、`sheet-insert-rows-at-start`、`sheet-insert-rows-after-first`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列与行的插入位置边界、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | -| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand`、`plugin-auto-fill-grid-tree-origin-value` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单 | +| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand`、`plugin-auto-fill-grid-tree-origin-value`、`plugin-excel-delete-range` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单、Delete 清空可编辑选区 | | 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose`、`disable-hover-columns`、`select-highlight-in-range`、`select-header-scroll-top`、`double-click-auto-column-width`、`double-click-auto-width-height` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | | 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header`、`api-update-columns-on-mouseleave`、`api-update-columns-after-selection` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | | 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | @@ -20,17 +20,17 @@ Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移 ## BugServer 未选候选去向(2026-09-24) -已审阅的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 59 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 +已审阅的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 67 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 | 去向 | 数量 | 含义 | | --- | ---: | --- | -| 已迁入本地用例 | 59 | 51 个新模块,以匿名数据重建配置及动作 | +| 已迁入本地用例 | 67 | 58 个新模块,以匿名数据重建配置及动作 | | 隐私风险排除 | 19 | 发现业务化字段或数值,原始内容没有进入仓库 | | 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | | 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | -| 大型源码待缩减 | 70 | 需要缩成匿名且仍保留关键边界的数据 | +| 大型源码待缩减 | 68 | 需要缩成匿名且仍保留关键边界的数据 | | 交互未证明覆盖 | 136 | 录制动作缺少对应的本地动作与断言 | -| 静态配置未证明覆盖 | 212 | 配置或数据变体缺少对应的本地断言 | +| 静态配置未证明覆盖 | 206 | 配置或数据变体缺少对应的本地断言 | 三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有包含订单和客户标识的主从表来源、包含业务流程信息的 Gantt 来源排除。独立的 `api-change-cell-values` 与 `gantt-resize-task-list-header` 使用匿名固定数据,不关联被排除来源 ID。 @@ -38,10 +38,10 @@ Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移 已补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 197/197 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 +新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 204/204 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 本轮新增可验证场景:Sheet 在第二列和第三列前插列,以及首条和第二条记录前插行,已用实际数值位置断言;列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 本轮新增列级悬停禁用、跨表头选择、滚动后表头选择、鼠标事件回调更新列、拖动及双击列宽、插件填充柄复制、千行复选框、透视排序规则更新和透视图框选。另将 7 条含订单/客户标识或人员邮箱字段的来源标为隐私排除。 -这份台账是可继续处理的缺口清单,尚不能据此判断 BugServer 用例迁移已经完成。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 +最后一轮定向补充 7 个模块、8 条真实来源 ID:合并链接、透视指标隐藏与冻结、连续色彩图例、PivotTable 图表标记线、面积图、玫瑰图、Excel 键盘删除选区。按“绝大多数配置和模块有代表用例”的标准,迁移已基本完成;台账中的剩余候选仍可用于未来针对具体缺陷选例,不应按未迁条数推断覆盖率。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 diff --git a/packages/vtable/__tests__/visual/cases/cells/link-merged-auto-height.mjs b/packages/vtable/__tests__/visual/cases/cells/link-merged-auto-height.mjs new file mode 100644 index 0000000000..bcfd1b6d57 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/cells/link-merged-auto-height.mjs @@ -0,0 +1,47 @@ +/** + * BugServer case IDs: 6a8597d0a44900005e2b8e47 + * 验证目的:合并的链接单元格在自动行高下绘制,点击时不跳转。 + * 改写:把来源的长列表缩为三个匿名记录和公开示例地址。 + */ +export default { + mount(container) { + // 保留来源的 link、mergeCell、linkDetect、linkJump 组合。 + return new window.VTable.ListTable(container, { + columns: [ + { field: 'site', title: 'Link', width: 240, cellType: 'link', mergeCell: true, + linkDetect: true, linkJump: false }, + { field: 'value', title: 'Value', width: 120 } + ], + records: [ + { site: 'https://example.com/guide', value: 'A' }, + { site: 'https://example.com/guide', value: 'B' }, + { site: 'https://example.com/help', value: 'C' } + ], + heightMode: 'autoHeight', defaultRowHeight: 'auto' + }); + }, + async exercise(page) { + // 点击首个链接,确认 linkJump:false 不会离开本地测试页。 + const before = page.url(); + const point = await page.evaluate(() => { + const bounds = window.__visualTable.getCellRect(0, 1).bounds; + const host = document.getElementById('table').getBoundingClientRect(); + return { x: host.x + bounds.x1 + 35, y: host.y + bounds.y1 + 12 }; + }); + await page.mouse.click(point.x, point.y); + if (page.url() !== before) throw new Error('禁用跳转的链接离开了测试页'); + await page.mouse.move(760, 560); + }, + async verify(page) { + // 单元格类型与合并范围都必须由运行时布局实际识别。 + await page.evaluate(() => { + const table = window.__visualTable; + if (table.getCellType(0, 1) !== 'link') throw new Error('链接类型未生效'); + if (table.getCellOriginValue(0, 1) !== 'https://example.com/guide') + throw new Error('链接值不正确'); + const range = table.getCellRange(0, 1); + if (range.start.row !== 1 || range.end.row !== 2) + throw new Error('连续链接单元格未合并'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/index.mjs b/packages/vtable/__tests__/visual/cases/index.mjs index bc9505b359..1072fdd97c 100644 --- a/packages/vtable/__tests__/visual/cases/index.mjs +++ b/packages/vtable/__tests__/visual/cases/index.mjs @@ -197,6 +197,13 @@ export const cases = [ { id: 'scrollbar-ignore-frozen', purpose: '主横向滚动条跨越冻结列宽度', file: './frozen/scrollbar-ignore-frozen.mjs', bundles: ['vtable'] }, { id: 'frozen-empty-records-header', purpose: '大量列滚动后清空记录保留冻结表头', file: './frozen/empty-records-header.mjs', bundles: ['vtable'] }, { id: 'checkbox-header-options', purpose: '复选框表头回调固定选中与禁用配置', file: './cells/checkbox-header-options.mjs', bundles: ['vtable'] }, + { id: 'link-merged-auto-height', purpose: '合并链接单元格在自动行高下禁用点击跳转', file: './cells/link-merged-auto-height.mjs', bundles: ['vtable'] }, + { id: 'pivot-indicator-hide-frozen', purpose: '按列隐藏透视指标并冻结右列与底行', file: './pivot/indicator-hide-frozen.mjs', bundles: ['vtable'] }, + { id: 'pivot-color-legend-order', purpose: '透视表标题先于顶部连续色彩图例布局', file: './pivot/color-legend-order.mjs', bundles: ['vtable'] }, + { id: 'pivot-chart-spec-mark-line', purpose: '透视表回调图表配置及面积图阈值标记线', file: './pivot/chart-spec-mark-line.mjs', bundles: ['vchart'] }, + { id: 'pivot-chart-area-axis-sort', purpose: '启用坐标轴排序配置的双系列透视面积图', file: './pivot-chart/area-axis-sort.mjs', bundles: ['vchart'] }, + { id: 'pivot-chart-rose-indicator-title', purpose: '透视玫瑰图与可见指标标题', file: './pivot-chart/rose-indicator-title.mjs', bundles: ['vchart'] }, + { id: 'plugin-excel-delete-range', purpose: 'Excel 键盘插件通过 Delete 清空可编辑选区', file: './plugins/excel-delete-range.mjs', bundles: ['plugins', 'editors'] }, ]; /** 从当前清单目录加载用例,冻结副本不会回到工作区取代码。 */ diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/area-axis-sort.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/area-axis-sort.mjs new file mode 100644 index 0000000000..55885dd583 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/area-axis-sort.mjs @@ -0,0 +1,38 @@ +/** + * BugServer case IDs: 6541cdd044dadd6b7cb441cd + * 验证目的:PivotChart 面积图启用 sortDataByAxis 并绘制两组输入点。 + * 改写:把来源的大型透视数据缩成匿名的三期两组记录。 + */ +export default { + mount(container) { + // sortDataByAxis 保留来源的面积图轴排序配置。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + return new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['bucket'], indicatorsAsCol: false, + indicators: [{ indicatorKey: 'value', title: 'Area', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'area', data: { id: 'data' }, xField: 'period', yField: 'value', + seriesField: 'series', sortDataByAxis: true, animation: false } }], + records: [ + { group: 'G', bucket: 'One', period: 'P3', series: 'A', value: 7 }, + { group: 'G', bucket: 'One', period: 'P1', series: 'A', value: 3 }, + { group: 'G', bucket: 'One', period: 'P2', series: 'A', value: 5 }, + { group: 'G', bucket: 'One', period: 'P2', series: 'B', value: 4 }, + { group: 'G', bucket: 'One', period: 'P3', series: 'B', value: 6 }, + { group: 'G', bucket: 'One', period: 'P1', series: 'B', value: 2 } + ], + defaultRowHeight: 270, defaultHeaderRowHeight: 40, + defaultColWidth: 550, defaultHeaderColWidth: 80, widthMode: 'standard' + }); + }, + async verify(page) { + // 确认实际建立面积图单元格,具体区域形状由视觉快照比较。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 1) throw new Error('面积图单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot-chart/rose-indicator-title.mjs b/packages/vtable/__tests__/visual/cases/pivot-chart/rose-indicator-title.mjs new file mode 100644 index 0000000000..c41c5cfbb3 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot-chart/rose-indicator-title.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 695347df862ee80066b9cc60 + * 验证目的:PivotChart 玫瑰图显示指标标题和两组扇形数据。 + * 改写:保留 rose、角度及系列字段,删除来源的大型指标数据。 + */ +export default { + mount(container) { + // 使用本地 VChart 绘制 rose,避免来源的远程依赖和动画波动。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + return new window.VTable.PivotChart(container, { + rows: ['group'], columns: ['period'], indicatorsAsCol: false, hideIndicatorName: false, + indicators: [{ indicatorKey: 'value', title: 'Amount', cellType: 'chart', chartModule: 'vchart', + chartSpec: { type: 'rose', data: { id: 'data' }, categoryField: 'category', + valueField: 'value', seriesField: 'series', outerRadius: 0.82, + innerRadius: 0, animation: false } }], + records: [ + { group: 'G', period: 'P', category: 'A', series: 'One', value: 7 }, + { group: 'G', period: 'P', category: 'B', series: 'One', value: 11 }, + { group: 'G', period: 'P', category: 'C', series: 'One', value: 5 }, + { group: 'G', period: 'P', category: 'A', series: 'Two', value: 4 }, + { group: 'G', period: 'P', category: 'B', series: 'Two', value: 8 }, + { group: 'G', period: 'P', category: 'C', series: 'Two', value: 10 } + ], + defaultRowHeight: 300, defaultHeaderRowHeight: 40, + defaultColWidth: 480, defaultHeaderColWidth: 130, widthMode: 'standard' + }); + }, + async verify(page) { + // 指标标题与 rose 图表单元格必须进入实际布局。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts < 1 || table.colCount < 1 || table.rowCount < 2) + throw new Error('玫瑰图或指标标题未建立'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/chart-spec-mark-line.mjs b/packages/vtable/__tests__/visual/cases/pivot/chart-spec-mark-line.mjs new file mode 100644 index 0000000000..00fad71032 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/chart-spec-mark-line.mjs @@ -0,0 +1,40 @@ +/** + * BugServer case IDs: 65d572a597cc3d008de5b5a4 + * 验证目的:PivotTable 图表指标使用回调生成面积图,并绘制固定阈值标记线。 + * 改写:将来源的气温表缩为两组固定数值,去除远程图表加载。 + */ +export default { + mount(container) { + // 图表数据由记录的 trend 数组提供,markLine 在每个透视单元格内绘制。 + window.VTable.register.chartModule('vchart', window.VChart.default ?? window.VChart); + window.__pivotChartSpecCalls = 0; + return new window.VTable.PivotTable(container, { + rowTree: [{ dimensionKey: 'group', value: 'A' }, { dimensionKey: 'group', value: 'B' }], + columnTree: [{ indicatorKey: 'trend', value: 'Trend' }], + indicators: [{ indicatorKey: 'trend', title: 'Trend', cellType: 'chart', chartModule: 'vchart', + chartSpec: () => { + window.__pivotChartSpecCalls++; + return { type: 'area', data: { id: 'data' }, xField: 'period', yField: 'value', + animation: false, markLine: [{ y: 5, + line: { style: { stroke: '#222', lineDash: [5, 5], lineWidth: 2 } } }] }; + } }], + records: [ + { group: 'A', trend: [{ period: 'P1', value: 2 }, { period: 'P2', value: 7 }, { period: 'P3', value: 4 }] }, + { group: 'B', trend: [{ period: 'P1', value: 3 }, { period: 'P2', value: 6 }, { period: 'P3', value: 8 }] } + ], + defaultRowHeight: 190, defaultColWidth: 530, defaultHeaderColWidth: 80 + }); + }, + async verify(page) { + // 运行时须进入图表配置回调并建立两个图表单元格。 + await page.evaluate(() => { + const table = window.__visualTable; + let charts = 0; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) + if (table.getCellType(col, row) === 'chart') charts++; + if (charts !== 2 || window.__pivotChartSpecCalls < 2) + throw new Error('PivotTable 图表回调或标记线单元格缺失'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/color-legend-order.mjs b/packages/vtable/__tests__/visual/cases/pivot/color-legend-order.mjs new file mode 100644 index 0000000000..83c504486d --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/color-legend-order.mjs @@ -0,0 +1,35 @@ +/** + * BugServer case IDs: 6979f44b20f246006732267e + * 验证目的:PivotTable 的标题先于顶部连续色彩图例布局。 + * 改写:用四条匿名记录替代来源的大型数值表和远程图表资源。 + */ +export default { + mount(container) { + // 保留 title、color legends 和 componentLayoutOrder 的组合。 + return new window.VTable.PivotTable(container, { + rows: ['group'], columns: ['category'], indicators: ['amount'], + records: [ + { group: 'A', category: 'X', amount: 20 }, + { group: 'A', category: 'Y', amount: 40 }, + { group: 'B', category: 'X', amount: 60 }, + { group: 'B', category: 'Y', amount: 80 } + ], + title: { text: 'Color range', orient: 'top', align: 'center' }, + legends: { type: 'color', orient: 'top', position: 'start', + colors: ['rgb(235,235,255)', 'rgb(35,35,255)'], value: [0, 100], min: 0, max: 100 }, + componentLayoutOrder: ['title', 'legend'], + defaultColWidth: 160, defaultHeaderColWidth: 100 + }); + }, + async verify(page) { + // 检查图例生成可见边界,绘制顺序由截图比较。 + await page.evaluate(() => { + const table = window.__visualTable; + const legend = table.internalProps.legends?.[0]?.legendComponent; + if (!legend || legend.AABBBounds.width() < 20 || legend.AABBBounds.height() < 10) + throw new Error('连续色彩图例未绘制'); + if (!table.internalProps.title || table.getDrawRange().top < 30) + throw new Error('标题与图例未占据顶部布局'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/pivot/indicator-hide-frozen.mjs b/packages/vtable/__tests__/visual/cases/pivot/indicator-hide-frozen.mjs new file mode 100644 index 0000000000..4ca9fa2169 --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/pivot/indicator-hide-frozen.mjs @@ -0,0 +1,45 @@ +/** + * BugServer case IDs: 676a70de0982bf00b14e2316, 654311df0dc4c5635dc0d9ee + * 验证目的:按列维度隐藏指定指标,同时保留右侧列和底部行冻结。 + * 改写:把来源的多级地区和商品数据缩为两个匿名维度值。 + */ +export default { + mount(container) { + // B 列的 count 被隐藏,A 列的两个指标仍显示。 + window.__pivotHidePaths = []; + return new window.VTable.PivotTable(container, { + rows: ['group'], columns: ['category'], indicatorsAsCol: true, + indicators: [ + { indicatorKey: 'amount', title: 'Amount' }, + { indicatorKey: 'count', title: 'Count', hide({ dimensionPaths }) { + const values = dimensionPaths.map(path => path.value); + window.__pivotHidePaths.push(values); + return values.includes('B'); + } } + ], + records: [ + { group: 'G1', category: 'A', amount: 11, count: 17 }, + { group: 'G1', category: 'B', amount: 23, count: 29 }, + { group: 'G2', category: 'A', amount: 31, count: 37 }, + { group: 'G2', category: 'B', amount: 41, count: 43 } + ], + rightFrozenColCount: 1, bottomFrozenRowCount: 1, + defaultColWidth: 135, defaultHeaderColWidth: 90, widthMode: 'standard' + }); + }, + async verify(page) { + // 唯一的 B/count 数值不可见,其余指标与冻结数量必须保留。 + await page.evaluate(() => { + const table = window.__visualTable; + const values = []; + for (let row = 0; row < table.rowCount; row++) + for (let col = 0; col < table.colCount; col++) values.push(table.getCellOriginValue(col, row)); + if (![11, 17, 23, 31, 37, 41].every(value => values.includes(value)) || + values.includes(29) || values.includes(43)) + throw new Error('透视指标隐藏结果错误'); + if (!window.__pivotHidePaths.some(paths => paths.includes('B')) || + table.rightFrozenColCount !== 1 || table.bottomFrozenRowCount !== 1) + throw new Error('隐藏回调或冻结配置未生效'); + }); + } +}; diff --git a/packages/vtable/__tests__/visual/cases/plugins/excel-delete-range.mjs b/packages/vtable/__tests__/visual/cases/plugins/excel-delete-range.mjs new file mode 100644 index 0000000000..39e63f30ae --- /dev/null +++ b/packages/vtable/__tests__/visual/cases/plugins/excel-delete-range.mjs @@ -0,0 +1,46 @@ +/** + * BugServer case IDs: 69292cda9995e4005d1533c2 + * 验证目的:ExcelEditCellKeyboardPlugin 用 Delete 清空选中的可编辑矩形范围。 + * 改写:以匿名短记录替换来源的姓名和邮箱;保留源码中的键盘动作。 + */ +export default { + mount(container) { + // 编辑器使插件默认的“仅清空可编辑单元格”规则有可验证目标。 + const VTable = window.VTable; + VTable.register.editor('input-editor', new VTable.editors.InputEditor({})); + return new VTable.ListTable(container, { + columns: [ + { field: 'id', title: 'ID', width: 80 }, + { field: 'name', title: 'Name', width: 150, editor: 'input-editor' }, + { field: 'score', title: 'Score', width: 120, editor: 'input-editor' } + ], + records: [ + { id: 1, name: 'A', score: '10' }, + { id: 2, name: 'B', score: '20' }, + { id: 3, name: 'C', score: '30' } + ], + editCellTrigger: ['keydown'], + plugins: [new VTable.plugins.ExcelEditCellKeyboardPlugin()] + }); + }, + async exercise(page) { + // 真实焦点、范围选择和 Delete 键与来源的内联动作一致。 + await page.evaluate(() => { + const table = window.__visualTable; + table.selectCells([{ start: { col: 1, row: 1 }, end: { col: 2, row: 2 } }]); + table.getElement().tabIndex = 0; + table.getElement().focus(); + }); + await page.keyboard.press('Delete'); + }, + async verify(page) { + // 所选四格必须清空,未选记录及不可编辑 ID 保持原值。 + await page.evaluate(() => { + const table = window.__visualTable; + for (const row of [1, 2]) for (const col of [1, 2]) + if (table.getCellOriginValue(col, row) !== '') throw new Error('选中范围未全部清空'); + if (table.getCellOriginValue(0, 1) !== 1 || table.getCellOriginValue(1, 3) !== 'C') + throw new Error('Delete 修改了未选或不可编辑单元格'); + }); + } +}; From 3f962965f6553937e3f39d95c3c3f47e48d4bf4e Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 24 Sep 2026 18:06:22 +0800 Subject: [PATCH 9/9] docs: finalize visual case migration guidance --- AGENTS.md | 9 + .../cases/BUGSERVER_CANDIDATE_TRIAGE.json | 10937 ---------------- .../vtable/__tests__/visual/cases/COVERAGE.md | 57 +- .../vtable/__tests__/visual/cases/README.md | 4 +- 4 files changed, 26 insertions(+), 10981 deletions(-) create mode 100644 AGENTS.md delete mode 100644 packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..1a5b46f4f3 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ +# VTable 开发约定 + +## 本地视觉测试 + +- 使用 Node.js 22,在仓库根目录运行视觉测试。开发完成后按改动范围执行相关单例或目录,例如 `node packages/vtable/scripts/visual-test.mjs --case list-basic` 或 `node packages/vtable/scripts/visual-test.mjs --dir pivot`;影响多个模块时扩大测试范围。 +- 提交 PR 前运行全量:`node packages/vtable/scripts/visual-test.mjs`。检查报告中的基线、当前和差异图;执行错误或无法运行时如实说明,不把 `--self-compare` 当作官方基线通过,也不通过跳过断言或放宽阈值掩盖差异。 +- 新增功能、修复 bug 或发现覆盖空缺时,可以新增有明确目的的确定性用例,或补强现有用例。新用例登记在 `packages/vtable/__tests__/visual/cases/index.mjs`;交互用例须执行真实动作并断言结果。新增或修改用例先运行单例 `--self-compare`,再运行相关目录。 +- 开发者或编码 Agent 独立新增的用例**完全省略** `BugServer case IDs` 行,不填写空值、占位或虚构 ID。由现有 BugServer case 迁移的用例保留真实来源 ID,合并来源时列出全部真实 ID。未来同步到 BugServer 成功后,再补写服务返回的真实 ID;本期没有同步脚本。 +- 环境准备、报告和清理见 [视觉测试说明](./packages/vtable/__tests__/visual/README.md);目录与用例格式见 [用例指南](./packages/vtable/__tests__/visual/cases/README.md)。本次任务启动的浏览器、服务和其他测试进程在结束时应停止。 diff --git a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json b/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json deleted file mode 100644 index ab393102c0..0000000000 --- a/packages/vtable/__tests__/visual/cases/BUGSERVER_CANDIDATE_TRIAGE.json +++ /dev/null @@ -1,10937 +0,0 @@ -{ - "product": "VTable", - "sourceSnapshotDigest": "de03690e63b7859f62ae14d4efc521951a1ce71d9d5db33881bcf98c37b54d1c", - "officialBaselineSha": "4e5ce4540dc5fb223360d5d7c08efdcfd56b3d78", - "method": "A migrated entry names an executed local case and its assertion. Deferred entries are explicitly unproven; shared option names or AST shapes do not establish equivalence.", - "counts": { - "baseline_failure": 1, - "deferred_interaction": 136, - "deferred_large_source": 68, - "deferred_resource": 31, - "deferred_static": 206, - "migrated": 67, - "privacy_excluded": 19 - }, - "entries": [ - { - "id": "64744dfe5d221c008666ee0f", - "sourceDigest": "0513512ecf16f0fe15276a214a1f4cec6057f7d98d1d47968981185cb9e26deb", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64744fa75d221c008666ee11", - "sourceDigest": "ed5a898b97b2b53fba66fd3ef435185e1fa77dc0adbfcd61640268eca19a3035", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "647450855d221c008666ee14", - "sourceDigest": "a6705fcf4831ede468bba0e1a14a84d1f9844eb60f4d7e76fdea791b3db2e41e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6474516f5d221c008666ee15", - "sourceDigest": "d183029f0da17e023895cc8b35813381d16a3f325809f5bf93be89b12c2e7825", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [ - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "647451ed5d221c008666ee16", - "sourceDigest": "b78b192dcabb36cf0b347398b0dc147e930da3591110cc3fcb506fddb6286c6e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6474534d5d221c008666ee18", - "sourceDigest": "ee1574cf4d8f6b80dc4bbac27994c8a8c1de68315575f819e8ab951986f2b354", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-column-header-title", - "verification": "columnHeaderLevelCount" - }, - { - "id": "6474549f5d221c008666ee1b", - "sourceDigest": "9f8d2b8d931313aecd3b5a9bb4e3603de5fd6ab80b01d0f6a0ce0385ff4a121e", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6474561b5d221c008666ee1c", - "sourceDigest": "842aa9374f1756a3e448b4fde58e7ebed3ec916de38a6dd7c40c7a6140adcbb7", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "hover-cross", - "verification": "表头与表体真实悬停、cross 高亮状态及截图" - }, - { - "id": "647456e55d221c008666ee1d", - "sourceDigest": "fb69518e34b7fcf53d679c15ab36bf16c54657b058377dddfe92b43565f26540", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "64745a015d221c008666ee1e", - "sourceDigest": "0a80c0e7aaaae466aadbf4d94850e833ec9cd52fcf37f5853ee79f684fb90b5c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "64745a465d221c008666ee1f", - "sourceDigest": "7f29d689ad6ff1373b35a41b10266b3eb8cf86e5fc3bedecb72d55583ebf2a65", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "select-drag-outside", - "verification": "单选、拖选、表头选择、表外点击后的范围及截图" - }, - { - "id": "64745a8d5d221c008666ee20", - "sourceDigest": "df900a36cea450fcf3707c09e7d520f6f6304e72dce468c8182d7e60024ca3e2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "64745b055d221c008666ee21", - "sourceDigest": "9f52735cff829c20160fbf258f5454fecf2e10b458a6a68a67242f26de061212", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "64745c2d5d221c008666ee24", - "sourceDigest": "2a5b5a786d6cda2e2a377e818668d2f1261f4cf0a8286e095a342f4cdee609c8", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 8, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "64745e5b5d221c008666ee26", - "sourceDigest": "91507f3cc89f93bad126555b003f924d1b5fdc5d8bc574ea804fad2955f853e8", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "autoFillWidth", - "autoFillHeight", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "64745ea95d221c008666ee27", - "sourceDigest": "56ae5acfd5d3e70912826b76551909991bfc2c5bc075bb77d31c7341612e5ecf", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64745f015d221c008666ee28", - "sourceDigest": "3cf949637e213f3b0b089503730e0bd68a70f507a41843efa329b706d4246ea1", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "647461145d221c008666ee2a", - "sourceDigest": "72d35721910eeade85b76e179ede5ece435852552104bb065567a037d1bd1fa6", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "647461665d221c008666ee2b", - "sourceDigest": "6d2837b80cc47bff05ad17bdf6259dac66accb413e1867abe3e0b6b96f8f79a1", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6479bcfbc48954008d952e0e", - "sourceDigest": "f459933015d76abe8b3062b41fcb2e05543b3c58c34f4fa5f330b890df1e46d7", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6479bdf9c48954008d952e1a", - "sourceDigest": "8bbfa19061dbfad27ebe1a99edb4c0647f8e94970a3d0563662bf1b332353fac", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 6, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6479c059c48954008d952e2f", - "sourceDigest": "05ce851ee2de6291c4b40abdf880be0af80d50970bf1d409b00727ddcb172b58", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6479c0d0c48954008d952e31", - "sourceDigest": "684b7ca5ec0339c45710c739f4aa5a680fc0d17d1500bc3f987e5fdf8b3984f4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "647ddbb8733d2ab935925356", - "sourceDigest": "257b0c52a69045101122e56e770190f9e02638fb3bfc6d95c316c3d2b5a8f3e4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "hover-row", - "verification": "表头与表体真实悬停、row 高亮状态及截图" - }, - { - "id": "647ddbcfeafb6dd17a28869b", - "sourceDigest": "dc5415ac9ecf49f97d4fdc0456cf049d11629a47c90efe50d91a9155ccd86c0f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "hover-column", - "verification": "表头与表体真实悬停、column 高亮状态及截图" - }, - { - "id": "647ddbf6eafb6dd17a28869c", - "sourceDigest": "40747f9902a51e099db526363f1b23e2557f5bd3fa737bf639e30e4b497d4373", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "hover-single", - "verification": "表头与表体真实悬停、single 高亮状态及截图" - }, - { - "id": "64b780578973e285ed4e5e0c", - "sourceDigest": "e19f7f7a25f54d3da32a623d8303cf6c5a22f148c2b279c4cb86847b60397a94", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 5, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "64b7866cf1af57b472231ca8", - "sourceDigest": "5258c22516706d1950b320827c0d64d922d1311a7d833e697462962bbe022dd0", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "64b78a7ef1af57b472231ca9", - "sourceDigest": "0a8c4d835a87078a2d77c0046ed59a4351e2de805e0a0cee076efc7cd661c819", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64b78b20f1af57b472231caa", - "sourceDigest": "a7e2e4b03f79572706f93e26135c2dd832d6714a5f0d5ec534869e55f50ebe4f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64b78beef1af57b472231cac", - "sourceDigest": "dab041442ce352a5f7d81871371b4b04cf2eb99dec8dc3d849c626a96979ff3f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "transpose-only-body-auto-width", - "verification": "getColWidth" - }, - { - "id": "64b899a4dc862dee5aa013ff", - "sourceDigest": "1b77f941c133d4996ef3c5d3b9f07e8234d421c3b853b58748b7f5ff9062c67c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64b9ec8fe563e8374f45e68b", - "sourceDigest": "01adae7ac395b031058f13df87073e5c8e81a78f11c199b24766f0122a072886", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64b9ef89bd5c995da3237575", - "sourceDigest": "0d98d759334fa656cd994718ddfc63616cea505c4ee484485b1e6365829a9eb9", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "64b9f05724402a7e07da8e3b", - "sourceDigest": "6e9e55333d72b0546fb70c6fed813b3f5e03935fe9b9051ab87a55a279be8d3b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 3, - "optionSignals": [ - "indicatorsAsCol", - "legends", - "brush" - ], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "64b9f06824402a7e07da8e3c", - "sourceDigest": "ef9876381c4f9c8dd6e12708f3cfef618ca774369d48295cba57284e68cbc1a9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-limit-max-auto-width", - "verification": "getColWidth" - }, - { - "id": "64b9f13dbd5c995da3237576", - "sourceDigest": "9343d4e4ba37247e94d5da34490bfce2d40d4ab52d8b95aade36181896789ccf", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64bdfcd05134109a76ccddd3", - "sourceDigest": "69c05b33b5579dcc8a565b94805718d59ca9e52e47445376c84a2b13d0cf053b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64bdfd775134109a76ccddd4", - "sourceDigest": "2a1ce735c05a31eb3070761f30e4266f57d8c2d1d2cc36ac12265fc4562ad10a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "autoFillHeight" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64bdff855134109a76ccddd7", - "sourceDigest": "bfc04fbf4a121ded3d8ddeca59334fb4afbf1078c1ae1a1ae874974b1a9baca8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64bdffc65134109a76ccddd8", - "sourceDigest": "9fcf4bf1034cca98f451e6612034b47294ff0690cfe00e88156098622bc638bb", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64be00875134109a76ccdddb", - "sourceDigest": "11a84815d67a6b107b0898a8b46138c84fd1861b5fba8338a4171c6b8dacbef3", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64be00db5134109a76ccdddc", - "sourceDigest": "8a0f5d51a5588b94e4288369d995556850a793e27c2001cd3fb90021074b5b3c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "heightMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64be017a5134109a76ccdddd", - "sourceDigest": "10f88b5d8bd8d3ccebe42708fdd41b2f6869d83a8c50c9af5bfb8e3f341356c5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "heightMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64c8fd3c6a0e890080b1aff6", - "sourceDigest": "272754dfa13705c4c9df3d64b92a6454d5145d93bec62d96f93779aff4b701e6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "heightMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64ca489ff22710ecb1c7e6fd", - "sourceDigest": "1e506ee97b1a465be0b667f6b80ea0570686126e3ff64bfdc4f5ad141d9167a9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64ca48f3f22710ecb1c7e6fe", - "sourceDigest": "a944213abeb7e43b818b54eebc59e64e19a98831e083804625bafda2c5bc3de9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "legends" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64d9ce2b064f3d06175b0f25", - "sourceDigest": "de8407dc2b1b7ae99583665d22e60c24d908faeddda0c38c92abe0d7e58c8e21", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "autoFillWidth", - "widthMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64d9cec3064f3d06175b0f26", - "sourceDigest": "0a77e4ad08d36a0556762f1b4551949199b3ad616fe51553338959664d4c6651", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "heightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64e869fd707420a88d0e6932", - "sourceDigest": "9c19a550166f85ae7e8db7e50eff2620b83c2592eccca0bc6426a579305f8fdf", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64ed8e7ed4858ce3fbd85ad5", - "sourceDigest": "b01a7278780471aa331aee9d9bff3776cd966e4717bfb8376e102a0e66de9b4b", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64ed8ed1d4858ce3fbd85ad6", - "sourceDigest": "29c5cd13436642605352757069c8bb167764eada63dd44ca5d667e134dc213c5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64ed8f3ed4858ce3fbd85ad7", - "sourceDigest": "b90653f8d141c964974f120635905b0714614f766bb0f9f52ae76117406984f4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64f5b9690f4df6126e128057", - "sourceDigest": "e4c9ca9d78a648f697e1b0116fe02db2e7d238760e4e0dcca5d7bc86e046ce1d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64f6cb47c380c3009a3e7e62", - "sourceDigest": "08ebc79d2f06705b3a3152e64dd21d5a8447bf7031289d2bd805b3756e9684ba", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64f7d8862937835bd5c893fa", - "sourceDigest": "5df1acdd056cc66c5407656809a20eb82d145cda84ebe63fab1c9fafab4c3ecc", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "pagination", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64f820a67d8f46008b2df45f", - "sourceDigest": "9994147130ecb7905d6211cce7954d78407cea89874aba003212decdf696bab8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "getCellValue", - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "64fa93512c50118f1f4dfe3c", - "sourceDigest": "ba41acd1e15d50a5b2b002ab474c2c581ff204b0a9cef01a06b0dc3556c90c44", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "frozenColCount", - "indicatorsAsCol" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64fa94442c50118f1f4dfe3d", - "sourceDigest": "fa8138164076cc00c0da522a681b3b66f435dd8e56593fb8a5106b1f604f19c4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount", - "indicatorsAsCol" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64fae5b614f81970d8db554a", - "sourceDigest": "be4341809514c7f82f894119f65b28c87dd980bdb30e12063694f51035edaa9e", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64fe83211754d74d66e96284", - "sourceDigest": "b1e2d1f5077fa59cfeb3a376e4b3636cec30b6bf871612e36b7476b7c09ff466", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "64fe8892bf9b5176ccd51408", - "sourceDigest": "8a6907768ef592ff6fd8008efbcebcdf68fb386832e13630cf97778f51a22614", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6500046296294da1e9b882fc", - "sourceDigest": "c2892e8e38abb86ed1d6f5f76e9ccaaa19be44484d3480d6d87c2c40e980c380", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "legends" - ], - "methodSignals": [ - "on" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "650195bdced2a800826bfff1", - "sourceDigest": "2a4c90905a00c6edad40f8accaeb476f60dee6391b5369a0f53da39a4f618b04", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65027716138232a1b6ffc39d", - "sourceDigest": "0b539de499b2148158cad19bfa1e32f63bdbf0d4568143ed7743a995ea7ef032", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "autoFillWidth", - "autoFillHeight", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "650835828f73d6fa71c7ef58", - "sourceDigest": "369542d4f2c0888a1533ad1504b2cafda837e975417b897b42f7caa93580acd8", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "650bb5840927bc458fdcef4f", - "sourceDigest": "098d890f475472c7d3aa077e42b4f01c46bc6317a42f75e12f14212be95e1968", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6524ffcaa876fe243b5148e9", - "sourceDigest": "0724312f4b8e9bc26d9e342f18850791a9b69d24915303a1f0676281a4a300b2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "autoFillWidth", - "autoFillHeight", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "652528d0a876fe243b51492b", - "sourceDigest": "51b7f7dd3aa80539f34d6754bf4b738f30cc3d2222f207ca75f1788d4124a393", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "6525294ba876fe243b51492c", - "sourceDigest": "633f1ee5da7e72db2452e555547121654cba96b48802b11f25a18ea75f6b21b3", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "652605dda876fe243b514956", - "sourceDigest": "b09db23ae56e8389761a7f5571efae2fb06f33715cbb80514fe518e6c9f14922", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65265a82b8b61fb2c4781aef", - "sourceDigest": "2d6e94cfa39f8437afc26a0d37e0db9420fefed93f2943556c052e530ba15b23", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65279aa795c0cdbd788cf15f", - "sourceDigest": "10315153ffacb0e57084330463c12a0976857bbbe5966d94d72366ca58df2388", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6527ac0695c0cdbd788cf17d", - "sourceDigest": "93317dee1c281151570b7880cdae8500120380a03bb999c68c035c87f15c38cf", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "autoFillHeight", - "widthMode", - "heightMode", - "frozenColCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "652cf14751d9f60a3c5cb89b", - "sourceDigest": "8a44df3c1fbdc4d3305d177f975ba3c493337bb614aa7bf697dfe803be9db954", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "652cf45351d9f60a3c5cb89d", - "sourceDigest": "c7e7a47eee28563b7f059a8fd96fda70b275da15ad462067b533d7445af4e964", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "652d0e6b52abb1c00ef7dd7e", - "sourceDigest": "e0a11cdc511167342c1281f639617bc8e388b7884584807d3c9289ac1af926d1", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "652df00752abb1c00ef7dda5", - "sourceDigest": "c02a46bc876323419d3252984dd2619a04b8bfc80fb11685f727968b63f3d6a6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "652df8a452abb1c00ef7ddb5", - "sourceDigest": "55ee0743d8dd4e8a7e177114ff0af802359e6fbcb2447f539338280a1a2e7797", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "652e01c41dd15a4ab522f751", - "sourceDigest": "33f4a46bcaec677c986b9a92b507bbc3a77837afe6625a60c2f40ed104d61bf4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6530df274b150fb4db03fb1d", - "sourceDigest": "d5c314e833b203a0ad8b0e68795f1206000ee038cf2f5418339ebc0479dcf3c8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6530e2138632117ed798a22c", - "sourceDigest": "a7e2e4b03f79572706f93e26135c2dd832d6714a5f0d5ec534869e55f50ebe4f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6531008b8632117ed798a26b", - "sourceDigest": "f1c0d6ecd3db70c62794a27056fdf2dc6ca0eda64016012b9a9dbfc73ddabad3", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "customLayout" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "653102ad8632117ed798a270", - "sourceDigest": "be09e73cee29e936aae1d28da64359d7013e723bc866d2118c1320f7849103b3", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-header-cell", - "verification": "表头点击后单格选择范围及截图" - }, - { - "id": "65322e87159a621b655d9eb9", - "sourceDigest": "63caa525a6d1c246d27e5065c38bca669e7aa70405f9a716133ea3fe0e3fcfbe", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6532320388cd1012fefa741c", - "sourceDigest": "96362f79a82ce0d8fb981423a1939524e2c7640ee72972323947c708dc8863f0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "autoFillWidth", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "layout-auto-fill-width-resize-container", - "verification": "dragged first-column width and remaining column after host resize" - }, - { - "id": "653249d776bd2d82b5ce5e67", - "sourceDigest": "b89a82076afdde8e8ef8b78b28ae4b82827edf120234f43e6b1b81b82ec3114b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "cellType", - "indicatorsAsCol", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "653649cb173c354c242a7c4e", - "sourceDigest": "6a5320c34a4c583e4d0515d2120c68213ec0846a28cb57e9b2c802e62326b0a2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65364a57173c354c242a7c4f", - "sourceDigest": "ffb42ee64757baf6b7449370f44fc7c77a26d197f1d7b3ac3c0162aedded2114", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65365114173c354c242a7c5a", - "sourceDigest": "b638a6874e6f55c9de57f605b599266f5799ffbba0bb5791cb531a0ac4d0fb88", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65365140173c354c242a7c5b", - "sourceDigest": "9ad214f48f3992c9752b8c205633fa6375200fab0f2739ca47085315d7148d49", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65388933159a621b655d9f6a", - "sourceDigest": "4a1c7cfe9ced3d703e7f6ac425976a4e9afd741cf9f529ab42e3db215cd8bfe5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [ - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "653b2f891053b2a37d5dc9b9", - "sourceDigest": "cc8c95f3bda86001ca09e3623f1512b194ce4b40b7f8cbe21ea2c5ebe407ab6b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "checkbox-over-thousand-rows", - "verification": "scroll beyond 1000 rows and checkbox state changes" - }, - { - "id": "6540b514f95bdcf7c340d701", - "sourceDigest": "23f20c824b531105cb64b5ade056d299dd001ebaec91af9b151cfebd4468a2c8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "autoFillWidth", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "layout-auto-fill-width-resize-container", - "verification": "stateManager resize, mouse drag and host width" - }, - { - "id": "6540b960f95bdcf7c340d702", - "sourceDigest": "dbb77f607f6653e2f95bf8448966d70c644487e8988937f9b67f8d0955f787db", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "autoFillWidth", - "autoFillHeight", - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6541cdd044dadd6b7cb441cd", - "sourceDigest": "1e1da6a7a26db7aad6534b2789d0d22ff1f788df40585ecb134ef58dddd8f95a", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "area" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "pivot-chart-area-axis-sort", - "verification": "area chart cell and rendered screenshot" - }, - { - "id": "6541ecf501e33ad70dc01e38", - "sourceDigest": "6f6cc8561efbc83a07dbce96d1afbcdcb0f2b8cdf80a0d7bec71fa28f1792c4b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "654311df0dc4c5635dc0d9ee", - "sourceDigest": "118aeb88f2da7e06c9d9114620e635fc8ca567b5e38a2ae7f5eb0ae98174aaf8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-indicator-hide-frozen", - "verification": "right and bottom frozen counts" - }, - { - "id": "654348a6b3dae69746d08701", - "sourceDigest": "0708bfd4782b2b8f4d2d549708dfccc83178e9fbbcc7e85c6b817ad4c792393d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "frozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65434afd0f2472008d41149f", - "sourceDigest": "68052434e540d211735ade0664a1b03625950a60a229030b7517c07f74bb44af", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortState", - "widthMode" - ], - "methodSignals": [ - "on" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6544ad1a4280163c75d7fa98", - "sourceDigest": "a9055bc8a356b75ac9ea7889825fbd26184538e3380e4eda98d9504d032388ed", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "disableSelect", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-column-disabled", - "verification": "列级禁选点击后无选择范围及截图" - }, - { - "id": "6544b3b14280163c75d7fa9b", - "sourceDigest": "20b29dcf09e4bedecdd37824aa8057d21a0c3ef14933ccc04827e2d930eb8016", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6548820a74e16908bc0462af", - "sourceDigest": "0ea08c5faa88292defe42b08f4fa9402da15db6d1f08927eb284f346349f6269", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65531b6c50997c335fecfcc8", - "sourceDigest": "4ad189ec1225a4d3060f35ff30112f88988b43039c0068ba765678e4244f0833", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6554a1059dabd71aa3845b5b", - "sourceDigest": "6fa6d7de9b0f53026c3ee06c01882e9a71a7a81faba1bc46a0e5333114e1cc09", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 3, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6554a2d39dabd71aa3845b5d", - "sourceDigest": "d82d96e522ab7b5ad23f637b57482ebf4a7de9c870b999dbe28191ef73c08f52", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6555c2b69dabd71aa3845baa", - "sourceDigest": "227027fc197bbd0ed4de844aa171c66ec337b7798d8c494114aee56fcae3bb1e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6555e6399dabd71aa3845bb7", - "sourceDigest": "4aad16ee12ecc25bffbfe34ef0345543ec74d0514126665c3aad34b1d5330801", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "double-click-auto-column-width", - "verification": "mouse drag then double-click changes measured width" - }, - { - "id": "6555f4339dabd71aa3845bb9", - "sourceDigest": "f3f056d8c5069e9a51ee3119c1769e23cfb32a864a9da6904f5cd3fce087e231", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "double-click-auto-width-height", - "verification": "double-click changes width with auto row height" - }, - { - "id": "6556050183c71200999f1f0c", - "sourceDigest": "9894cea9f613e77fc8f8c96b5a0e1623e78bf7d173333a0b049ba73153eb5f4f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6559c6a238a83fc5d230159e", - "sourceDigest": "3323ef7277188cccb77a3a4d32c213455e5061e708c4a69a89db24d54fecfbd0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "autoFillHeight" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "6559c76e38a83fc5d23015a1", - "sourceDigest": "188b429c5fd18e0247662496d36b6ac03243cb1155b54e3215103e3ab78aea35", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "autoFillHeight", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "6559c7c838a83fc5d23015a4", - "sourceDigest": "0524351df695c5891b9d600cc44f07ec9187ed359bae14defe5dd0bb856328b0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "autoFillHeight" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "layout-limit-max-auto-width", - "verification": "getColWidth" - }, - { - "id": "655b14d48ff2e4008d53a9b1", - "sourceDigest": "de0dfce98c86d3a472f7030194d375b822577f9f4f79352c01a6bcf5cdc9b1bb", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "655dc52112c3a41900817f36", - "sourceDigest": "0b2d5116106172965f51db0c0072127afc880c71dec18bbab585e30ae35b3ead", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "656582287bb49c240fa99c7a", - "sourceDigest": "c488595b6bb8a3821166f6d643b9d6418393a8a2f42cff17ee5ddaae73d03d8b", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6565b5717bb49c240fa99ccd", - "sourceDigest": "a17708f7fa951533ae7051fe3ca1cb3d4472cc9de7d1bc295d5d4c790bf0b186", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6565d1fe4c6c1a77d0efcc77", - "sourceDigest": "8ce18fb0473d73bbcfb0ba92521b740cc871b027d98db54152046a860db6d9aa", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6567f8ac66541d99f6bdfc3e", - "sourceDigest": "3ee7abdfa385add8d873f10209aecd268e46c52aa99a4b9829da833ab08314a9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6567fc0a66541d99f6bdfc42", - "sourceDigest": "118aeb88f2da7e06c9d9114620e635fc8ca567b5e38a2ae7f5eb0ae98174aaf8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6568014a66541d99f6bdfc4d", - "sourceDigest": "b2a3fe2dec3401d3b4e03a6ceaa351f000803db1289bbfe55556b815e38c5889", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "656803b766541d99f6bdfc51", - "sourceDigest": "173574ab6b2a16846f01038f39446bb215935bb35893423b63c28c902b3f7658", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "customMergeCell" - ], - "methodSignals": [ - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656987434c3611faee9b1a93", - "sourceDigest": "9b430ce0feec95f55a5d7d3a12d393bc5c98bc5f49122bf063da593efb4636a3", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65698a264c3611faee9b1a94", - "sourceDigest": "e6a86821836c7719ebf0b24799271d58ae71174089f5ec42f87771d55a4f681a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65698aed4c3611faee9b1a9b", - "sourceDigest": "560251d275467d1af5ed5302099c1c769ff808e2c843eb4399912c2c29999781", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6569af794c3611faee9b1ac4", - "sourceDigest": "242139e55363019b6a47531b21d9484113eb7586a241da8ceb058c78a4274183", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d86374c3611faee9b1b25", - "sourceDigest": "1b8de515bd5095dc3ccccccae0a8508bb36d0867239d4ab5d08212f7ed42a4a5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecord", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d91704c3611faee9b1b2d", - "sourceDigest": "107937e235f70c763bf183ce770cd83eb0fa367aadae7295570d402201c3a932", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d92cf4c3611faee9b1b2f", - "sourceDigest": "1d6c70c1eb755e768d4b663bbac7211fad46311267e4b10f7973a8adab3617fc", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d96194c3611faee9b1b31", - "sourceDigest": "04a6249eac7019af250e816d1c7678e34d69a48341769449af997b303a1a516c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d96c1eb24adef19a3a6d6", - "sourceDigest": "bded415e17c7779ddc5f4d8bb154df45ec512db0fb869c627a4514aa7492adb1", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656d99024c3611faee9b1b32", - "sourceDigest": "abad715874fc8762bccedf6c19dea330b4b9f16e4fd0febad4778385831a26fd", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656da0e04c3611faee9b1b34", - "sourceDigest": "07b46c7dc5800a6e926d41a5c87604baf01d88b2b34b785f89f34fcb1fdf4065", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656da1a04c3611faee9b1b35", - "sourceDigest": "84bd143834d662a6d7e821c1b632c4ef34c1a44014da3328969cc194eb1bba9a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656da1fa4c3611faee9b1b36", - "sourceDigest": "c8a30a2068b30ff4966c754840fac1538b73ad5afd1f518a135916b5ad0ebece", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656daa084c3611faee9b1b3b", - "sourceDigest": "479f8ab01207d174871e8c661eae713b913b83db7b055558979f895094e043dc", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "selectCells", - "setRecords", - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656daeb04c3611faee9b1b3c", - "sourceDigest": "2280f3d91e0472b636044ca29451f257d6fafa5665f3d8fb2329c02ccf74c21f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "selectCells", - "setRecords", - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "656dba6e4c3611faee9b1b51", - "sourceDigest": "39c7c5eb4bc1cfe6f3a60be1dafc31f7b0f817708eae8d76d23d6fbc4cfecd71", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "addRecord", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6570142144052e47f77c2925", - "sourceDigest": "3f920fd090d334c4bc7fe1b82dae8923f1ae3c1e5266e5c97cb6e3d291c54c56", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "657014a044052e47f77c2926", - "sourceDigest": "9714483f3f4cfc9d883c089f116fb539e0a9b6d6e49cc3776c38028ec4a289eb", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65701eb144052e47f77c2933", - "sourceDigest": "2e5391e1a918f7c35649a78c97f3fed6c9567e7d4780d1df27e0a55462ec25a8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "autoFillWidth" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6570227544052e47f77c293b", - "sourceDigest": "4ee8571d514f5dd9277c2bce7e7e8dc672f84ba3407d39805bf8c5167345e01c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "autoFillWidth" - ], - "methodSignals": [ - "setRecords", - "updateOption" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6570253344052e47f77c293e", - "sourceDigest": "53a42a7375066391c958d63873db9d2b6dcdb8d1110486fe4988e3dcabbda696", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6570258344052e47f77c293f", - "sourceDigest": "4f651fe8ef59b794a5a5078bc2df9c92be82a45cd813fba9b17acab2358a854d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "657068b644052e47f77c2976", - "sourceDigest": "736f3d39d7c90d4d82c63d599610ff322d9b8a729dedb6759ce3a63e3b826bdf", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "657068fc44052e47f77c2977", - "sourceDigest": "c9d74009022f66e2d95590f7f9f8cb79bb354a94aee64a9cb5b6fe0fb5fe55be", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "deleteRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6571638f44052e47f77c298c", - "sourceDigest": "a1e17f86949e82c92d2977ae67ecd6b3b23ca555686d37fb99c36c65fd984011", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "657163e944052e47f77c298d", - "sourceDigest": "24a919d4d0ab4490c092233aff374c1ce07126df311058aac943e8f6f0cda094", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "deleteRecords", - "setRecords", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "657191a244052e47f77c299e", - "sourceDigest": "00c242e5aad417c1789d3df92d76c4a03104d542c1d10789067e0083b726916e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6571b6fe44052e47f77c29a8", - "sourceDigest": "1d67b518160d917dd6775b63c9d22872d3b5a3c6b87fe1be1f1ae6f584f8d49f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "selectCell", - "setRecords", - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6572914344052e47f77c29bf", - "sourceDigest": "5399ed0b73e0124b53e8778d59256b07a63aabee7ae22fb8ebb04d16e9459008", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6572d31d55fadf4f41c7499c", - "sourceDigest": "f798c2b1ec259a1d4d89df649c95ee24c5c6a6378f2bff27ebb0afc2c822f694", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6572d47855fadf4f41c7499d", - "sourceDigest": "272b2338d73a9d8a18a5223022f761a9ece41c006e5f5c16abcafd4ce5b72ca5", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6576acf99196f8117d093511", - "sourceDigest": "b8ac907f29b10cf538dee3ee199134ca3f70b4a459efb14de69fd25a7f20dbd6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6576b5139196f8117d093512", - "sourceDigest": "8cfe52a9424fe1350bffd3a0abca90ab1ea50db59fc3439ed2c609052a23ffa4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6576d15b9196f8117d093520", - "sourceDigest": "05475d28ad4c3da31cddac04e3a0fe51325961cceefd194aec68228645bb0790", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65794bd87aaccfc82db37e98", - "sourceDigest": "99835b3a00c51f9c65e700d290e48d3cbcb76670c5cafcdfc45cd87c058fd5d8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "heightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6581698ceab07e0091708bab", - "sourceDigest": "8afa7c4cd7dd22c44a27da3874c8042e63e4f42205e0bbca00cd8766187be724", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "sortRules", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "pivot-custom-sort-click-colors", - "verification": "real sort-icon click + changed city order + two metric color mappings" - }, - { - "id": "65817239eab07e0091708bb8", - "sourceDigest": "1ae61432a8e5d515d5c598b8d4e353cdb93af318ae88c527b2dff568c0375ad7", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "658401ca807cf6008d99baa1", - "sourceDigest": "5d572cf5bffac7b197dc1796f1819c9a2fb019b137a3f63ac59daf2ba97ee9c9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "658404be807cf6008d99baa6", - "sourceDigest": "eabd0062704c454942fffd0b8dbbea8658063eb244b5715471588e464700dfdd", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "widthMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "select", - "disableSelect", - "highlightMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "658406f0807cf6008d99baab", - "sourceDigest": "d9ae1e04586eb69b0539c4b32da9c4b7b799e8676501cbaca6c7a99c175b03a9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "heightMode", - "frozenColCount", - "highlightMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6584086d807cf6008d99baad", - "sourceDigest": "1e8ad08be78b7f8f58d96d2956bda5d4f56491954107c7506859c7b0c82bfed5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "disable-hover-columns", - "verification": "hover.cellPos, disableHover and disableHeaderHover" - }, - { - "id": "658c0a1b9f48b900833db069", - "sourceDigest": "92d6ee213dbce1d2ade951996653d1703428ac99aaa77b51cce03116e973559c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "658ce50d70a7bfed368af60e", - "sourceDigest": "e7c687201d0efc5e5e1838108b5665ebee7119452daacd084510d45956e07314", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "658cf04020ffa2008c33eba2", - "sourceDigest": "b6e14ae0541b298a846f38f1f66951c218ddfa52c608ab3895f74ca1b053e34c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "pagination", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "658d566a20ffa2008c33ebf1", - "sourceDigest": "1593d12730815e51df19a09774c3ef80560c62f374628fcba70cd8df4ca2b276", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "disableSelect", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-global-disabled", - "verification": "全局禁选点击后无选择范围及截图" - }, - { - "id": "658d56ae20ffa2008c33ebf4", - "sourceDigest": "43575419fe21eaa943a8ba9b72ccc5b3115814570603b669cd57ef904829dd83", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "widthMode", - "select", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "select-header-disabled-drag", - "verification": "表头禁选点击与真实列拖动后的字段顺序及截图" - }, - { - "id": "658e984a20ffa2008c33ec28", - "sourceDigest": "52fdd58cb6144746f3fdd04c241fee1a84afd4209b74771f137d5a6fa5e31aed", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "658e9bdfad274f1e6d6d8964", - "sourceDigest": "0aa7d185e2bab3406ee9dec00ef9bf7ee06ce98d7d423e4cb89295ccd09541f7", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6593afc1c2aa2c00881fa911", - "sourceDigest": "09d0ee73950b7aef0aa67a4eed17bac1bcef4b20aafe2795a17d08cd019c3394", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6593ff4c0225f4008cc2b833", - "sourceDigest": "1130e6360b07f1484f42791eb811f5464997f42e09ddb13e942e5a24a7e0c79c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6594ca3134793a2f0e51ac63", - "sourceDigest": "245cadeb8bc28265429ccb5e19f1494726d2a4ee64d82893995e549840b48c4f", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "cellType", - "rightFrozenColCount" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "common", - "line" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65963357c3cfff93ba49edd6", - "sourceDigest": "52c0ce65fda58c6c90c9cb342f06edbdf8a420d3813994a2593c3dac6f916c11", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6596a56ec0a639008d8be557", - "sourceDigest": "7737706de1769b757fbb6d5de1020374a3ad7ee8a296de8726d03c65a24279ac", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6597c161c0a639008d8be583", - "sourceDigest": "5df89defe7625bfc5f61085660d5b49fe29721c313aab3993472897c61abff93", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "customLayout", - "cellType", - "rightFrozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6597c3d7c0a639008d8be585", - "sourceDigest": "d5dccb372b1f2d15196c83863670f2ec29e2a9606858155ac6cb09f1872c3f55", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "customLayout", - "cellType", - "rightFrozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6597f0c5c0a639008d8be59c", - "sourceDigest": "3f311d980701164dc17d4339d96a965435abeb81e901dc53b98ffb1979223fdb", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "changeCellValues", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" - }, - { - "id": "659e667c6040570085cd3eea", - "sourceDigest": "d8273e4fb2c3776a9d6912ea8e76f18a12a9d1052a5b17711edf6896c799d563", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "659e66ee6dc8940098194926", - "sourceDigest": "e2288dd700a8ca105b0bf2d5c7a4b2b7bad201b06f1e68c62e63913f5c1a7a9c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "659fac0e613711de69e3859e", - "sourceDigest": "68c0dc1d258c393c1777b4ea710f15317fcd7cf4f49bf0de0ac9edeafb68baa9", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "autoFillWidth", - "customLayout", - "cellType", - "rightFrozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "659fd5ef613711de69e385b9", - "sourceDigest": "5973f88937c5f1d49ebaff34c948390f3d49e079a3d648f85f680895e6535376", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "autoFillWidth", - "customLayout", - "cellType", - "rightFrozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "65a112755c6d60008335ece0", - "sourceDigest": "9a2e619a47213fe836890a232ff210f4365cf815951b89ed23243cbe027bf36a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "autoFillWidth", - "widthMode", - "cellType", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65a118f75c6d60008335ece1", - "sourceDigest": "922bf94b998a01d30975d1b6d85dde29c8db942d762c713f7aa14b9eb8531268", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "autoFillWidth", - "widthMode", - "cellType", - "frozenColCount", - "rightFrozenColCount", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65a501e1d0814f00842d407c", - "sourceDigest": "6c76e619449254e46a8b417695d3ebd4966c8bd86b12339b2d79e3950767f224", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "customMergeCell" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65a66b0f518457638fa485bd", - "sourceDigest": "2f65d56f0346f560003346500446fd18853d0e669787695ea6a39d5c1e2308e4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "pie" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65a66b94518457638fa485be", - "sourceDigest": "578ab58a178613608e74a5c5f92519988ca9d8123fff901eff2585c3c986a0da", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [ - "pie" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65a66c5c518457638fa485bf", - "sourceDigest": "c9cd3ac041b220ae60b0593ec09ec5a2078f6b5a256bad62aed4b77d6f8c8902", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "pie" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65a8ebbeabe49a7d3c712553", - "sourceDigest": "e1ea91b241c50ba6009e1c5f2776565cd58b65441424221f912eb78f95d9d6ef", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "bottomFrozenRowCount" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65a8ec24abe49a7d3c712555", - "sourceDigest": "312eeeaad94546552ad9ba6d231b00ce5ad74c2d308a374de54037b50aa5858d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "addRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65a9e004ebac688c39e91e22", - "sourceDigest": "9badcf0464f9c24860db1777b27f15b493f1ebbd9f3d918c1a9cd414fe6e2b20", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords", - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65aa128ece203f0089b9f7bc", - "sourceDigest": "7ee9f53c5dcf021d352c18e7a1f1cee8adaa5a1583aa668b49b9eca3cad9cfd4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecord" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65aa12f1ebac688c39e91e42", - "sourceDigest": "5887cc5685d78706805f009e1aaba8f70994945d01f1efe7c1e8b0be2804b612", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecord", - "addRecords", - "deleteRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65aa157febac688c39e91e46", - "sourceDigest": "858eec4032038b7ca6527c0e24b8f56fb31f63d82c7662d4289f7d9ea0dab305", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords", - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65aa46730cef8825bb267d9a", - "sourceDigest": "2aaeb1cce7bdb7c9938e03ea8ed319dcd0c905a3337d075bf59513ccad64dc3c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "dragHeaderMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65ae4071366fb000953feeaa", - "sourceDigest": "1eb351a00e3674fe4d17b1274c2924b0fa3c22dd16bcdc0632b0fff4e80e1db5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65ae4297366fb000953feeac", - "sourceDigest": "e5f45cdaa2249b1333b04aaaff7f288c943bcef1e555ceba1343b8fde8986353", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65ae4544366fb000953feeb1", - "sourceDigest": "b9057cf3dc7728fdab36db808c3b8016d7caea9dff3f246fc364f06ada70629b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "frozen-drag-disabled", - "verification": "getHeaderField + frozenColCount" - }, - { - "id": "65ae4667366fb000953feeb4", - "sourceDigest": "dd05e42e9fcea8a5370ed37e50f24c36200e13cf6231fe200f1c17b4be6d1a5d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "frozen-drag-adjust-count", - "verification": "getHeaderField + frozenColCount" - }, - { - "id": "65af6e6906085f008cf8f85f", - "sourceDigest": "bdb545a9ff1de2ba3dc094462a9c2cbe13713f9ff09fc90174acdc615495f803", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "updateColumns" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "api-update-columns-after-selection", - "verification": "click callback, updated header and selected range" - }, - { - "id": "65b2059f06085f008cf8f8f9", - "sourceDigest": "e20365509e2df39fb0a5cc205edf0fdbf02e99e249148211727aaa1b5c19dbe0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65b381c5de2002008ae46bbf", - "sourceDigest": "e5f45cdaa2249b1333b04aaaff7f288c943bcef1e555ceba1343b8fde8986353", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65b388fade2002008ae46bc7", - "sourceDigest": "9f4e32cf6806968f72c74110245d4a1937668ee70ab1c4ac4727a8d9f977cfcd", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65b717b2de2002008ae46bc9", - "sourceDigest": "b896f6d0408a9fdab88f9e677e133e06324abac27338425e72c91ed467f1fa20", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65b8764cecbd1000ab63334c", - "sourceDigest": "dbd50e67d43e284638ea0bb4dc5b98c3fbdc06e0bd945d01a731f0acce084bba", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65b8a178de2002008ae46be7", - "sourceDigest": "85d76f85004a26f2992b20b484c4faa322f5ac6dffd9b21728c2e75817a88400", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [ - "on", - "updateColumns" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65bdcd76ce3320008eecf684", - "sourceDigest": "fceedc9a879c1d30944a58d7e83803a43de6a35bf5d713d38a5ca6d795fc40e1", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65be113cce3320008eecf686", - "sourceDigest": "1098d8d1338334bfabddea1bd730c59ea2ec5743c558c78177a6fb83383ff7b4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "pivot-update-sort-rules-after-click", - "verification": "pivot sort click and updated region order" - }, - { - "id": "65c088a197cc3d008de5b484", - "sourceDigest": "24f461f0956a2570b95708eae55e0bfe4cf51a1dd36f765d5d7103d192069cc5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65c0951b97cc3d008de5b48c", - "sourceDigest": "1e588a8ff025271f017424e433413c1c7b2e6419a1cdadeab419a836d3f995b7", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65c0983d97cc3d008de5b495", - "sourceDigest": "232e6f5b301e0eafe15dc87bd4d265af3dfa9a5728d0b57f5cb07da02ccd2e62", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "65c09b2d97cc3d008de5b499", - "sourceDigest": "f6a4cbf35bcf10773e176373d60a0970a59999c824dbb957bda6dfb1030387e3", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65c1ce3f97cc3d008de5b4b9", - "sourceDigest": "37ff4490fc7a0d2472693457e0215b0565002bbf63744bc059509148255172b6", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "customMergeCell" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65c4729697cc3d008de5b55c", - "sourceDigest": "368904fe6598cf3c249109de8283d32bdbda668fa389ce7a9179ba28a7eecfb0", - "family": "list-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65d45c7a97cc3d008de5b576", - "sourceDigest": "edd51603be3b7382207c0855b103a1cd497bd9b38d6867abd47c3122ad3a8e3d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "updateColumns" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "api-update-columns-on-mouseleave", - "verification": "mouseleave callback, colCount and cell value" - }, - { - "id": "65d4948797cc3d008de5b593", - "sourceDigest": "1f73a44163ecd6adb46ee00c043d1885393f53636a4352cf1c9ea77e49141cc4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "cellType", - "transpose", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "scatter" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65d572a597cc3d008de5b5a4", - "sourceDigest": "9b4b0c78ec66233caee63efa1b6b516cad31ac931a94e5a3b867c55f49de5c1e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "select", - "disableSelect", - "markLine" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-chart-spec-mark-line", - "verification": "chartSpec callback and two chart cells" - }, - { - "id": "65d59c5d97cc3d008de5b5a7", - "sourceDigest": "ef228c0576131a018825fbcdac8dc00157419f8917d7b043f43f0db540c2ede8", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "customMergeCell", - "cellType", - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "getCellOriginValue" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "65dc3ddddb5fe000ad96fd7d", - "sourceDigest": "8125cdc2a58031fbdf54e4229362f1746d2380a38a880ad9f52dd4815a71c082", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65dc3eafdb5fe000ad96fd7e", - "sourceDigest": "8788c3dc724da2e6c7360fd5c07c55548141d2c291f8ee7e1e3d99715b519b7e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65dc4029db5fe000ad96fd7f", - "sourceDigest": "c5378eb488d2284192a9e78f9f1a0a168574275a1163614c2398e0c5bad9ec7c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "transpose-only-body-auto-width", - "verification": "getColWidth" - }, - { - "id": "65dc497adb5fe000ad96fd81", - "sourceDigest": "853c5944c8481834a649abf6fff56e01fa8da4d9232e7cd5df5a0f6c5e6bd595", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "cellType", - "select", - "indicatorsAsCol", - "markLine", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65e003cb1baf7300adb862e6", - "sourceDigest": "5b35b5c0fee154862c6361677d98f7b141103cbf30a3712f5bd8ab705c19618a", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "widthMode", - "heightMode", - "customLayout", - "cellType", - "frozenColCount", - "rightFrozenColCount", - "select", - "disableSelect", - "highlightMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "65e0291d1baf7300adb862f7", - "sourceDigest": "ff76af628d7c3b12e22b27511dc4b35e265449385243af9c30bb6f01c12d5251", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortState", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecordChildren", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65e5bb5b603de700d1d8b9e0", - "sourceDigest": "205bfb1a95701026127fdc44b05a03cb12c629a972363aac33ee37c234d2b17b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "changeCellValues", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" - }, - { - "id": "65e69335603de700d1d8b9e6", - "sourceDigest": "ceb5e0c37c35683384d4d55331a471aea1bac764e3e06f1ee7832ebb8bada2aa", - "family": "list-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "editor" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65e6d237603de700d1d8ba04", - "sourceDigest": "6127c54718de8b3b8738257ac7129a6df19d792e2bc6d94e414eb2a7c05cbf1b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65e6de57603de700d1d8ba06", - "sourceDigest": "f0b3b93f29d783dfe3e665464126188c0858b928d41569f1a2bd6ea3c81fdc17", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65e6ee9b686c6d00b99d7962", - "sourceDigest": "bccfee19e0f88d72226ad7f0cc6fa0d2d3c36cd8fa799c3fa4af0f3e611f9c9f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65e7d082603de700d1d8ba3c", - "sourceDigest": "c991c48337d2b6be84510b9d734e3386b5942d43594331dfe633d591c2ac005c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "editor", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "changeCellValues", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains person names and identifier-like values; excluded after user review; separate anonymous API case has no source-ID linkage" - }, - { - "id": "65e7d4da603de700d1d8ba3d", - "sourceDigest": "05e37116dbe3515b70e588c54ce7a4700899222450c18444c48b4ea8ac9abbc8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "pagination" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "65ea7cf27c3a0c00c99f2cd1", - "sourceDigest": "2c62bdb07185a4cfe769f0f4f7246550d4dd11dc28eb3a6d8ea3a68bdc12e54b", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "dragHeaderMode", - "widthMode", - "heightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f1260b7c3a0c00c99f2dad", - "sourceDigest": "c86bf94285b40bbc1d650683b8b1309bc4d24d7e89656b7502cbf3a575cbe2dd", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f3f85d7c3a0c00c99f2e1f", - "sourceDigest": "e7f469c2d84fcad5f8f6924446616eece047c71eebdd6ddc8a22351df1bc548c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f3f8e21baf7300adb8633f", - "sourceDigest": "d2a8da0d89deac447be87997a6ab363c19215afe363f4d3c588bfae0a7bf83f3", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "widthMode", - "rowSeriesNumber", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f3faab7c3a0c00c99f2e20", - "sourceDigest": "227238bcc1ed0a5bd0ea80d6ce75381051c6ddf79b6a3177834d3da96127d90c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "sortState", - "dragHeaderMode", - "dragOrder", - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "on", - "setRecordChildren" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f416ac7c3a0c00c99f2e21", - "sourceDigest": "0e2844f9f4a721f1d3f8d82eef57332944b8eb4f240431ea19c83cfc5c413871", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "showSort", - "pivotSortState", - "dragHeaderMode", - "dragOrder", - "widthMode", - "frozenColCount", - "rowSeriesNumber", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65f416fc7c3a0c00c99f2e22", - "sourceDigest": "e95c233e5197553e315a5580e043575ec13f0a87df65bcf1100edbe5b23097ef", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "widthMode", - "rowSeriesNumber", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "65fabcdc7c3a0c00c99f2e99", - "sourceDigest": "0b7c7b0af3c75d82c269cecf7253aca8ce1f720f762d39a504fdab26c99b3989", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "65fb9f5f7c3a0c00c99f2eb2", - "sourceDigest": "4be941c8c41ae073bc20af427b22ada54d0f085f4c65499532d82301fb175a96", - "family": "list-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "autoFillWidth", - "widthMode", - "heightMode", - "frozenColCount", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "65fc1171603de700d1d8bace", - "sourceDigest": "84bfa23a68ebebbb01aed5b8d22137aa2a806aaf4152bdb6106b884772808b7f", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "rowExpandLevel", - "showSort", - "widthMode", - "heightMode", - "select", - "headerSelectMode", - "highlightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "660130103b10c900bdd7d4a1", - "sourceDigest": "5750ff28befb5a215e0d81434cc53c97a7d87803714a6e1d8416ef65a09a0e8f", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 4, - "optionSignals": [ - "showSort", - "fillHandle", - "widthMode", - "editor", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6603e21c3b10c900bdd7d527", - "sourceDigest": "6e1e6d2c9c4202e09ec01dda1ae3cd6e84b7ff49527e40e733692f68efbbeeec", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66055e7ea8fccc00acd37038", - "sourceDigest": "bd9b1dce514e2a6784289766408e9777093b389d14aa81ae561ca0efb0db4b84", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "frozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66055ebca8fccc00acd37039", - "sourceDigest": "81b06f9fb768af46cb1e5d0d0b09f8346b82a8ef3f8e470a02cb27798e6d2caf", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "660bd37186babc00a5d92263", - "sourceDigest": "044361c03f52117a470f33690a5d260be148faeb5a1c882b2bb373981f509af5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "rowExpandLevel", - "dragHeaderMode", - "widthMode", - "heightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "660bd44f86babc00a5d92265", - "sourceDigest": "ba4a1c702146d5979e93bceb37a8584c71c234a2eb3190fd16baf0e83a9125e4", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "rowExpandLevel", - "dragHeaderMode", - "widthMode", - "heightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "660d09e236273600b2b8e9e4", - "sourceDigest": "5313e2ad078b70d0fcfc61a7fa949203d66da0dae5908340d2e1e86b06a716de", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66128a9036273600b2b8ea21", - "sourceDigest": "fc96ce4e5a25624b844ab482cb0e916e85c0afba6c60ed386ac7fec83983410c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66152cf42acd9c00d1c98a6d", - "sourceDigest": "462d68da8ae6634099763a7238ca7ee13313f99e0596c28aab164edbe218bb8a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "sortState", - "autoFillHeight", - "widthMode", - "heightMode" - ], - "methodSignals": [ - "on", - "setRecordChildren" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "661662461fb59800d262dc86", - "sourceDigest": "69c0279a57e43a98b3ac3e7dc38bffbffb3959e3bdc2fa168aaceb33846b2085", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6618db311fb59800d262dc94", - "sourceDigest": "deefed753fba802367ed11407bb604ee13ff60555514710dd7a20bb5dc33ab56", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "661ca9931fb59800d262dc96", - "sourceDigest": "5d504162f703c2e382495468fa3faf8d0e2cdd517485218d89b334763a7b1420", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "661caa0c1fb59800d262dc97", - "sourceDigest": "7120cd6f717481b3d027ecce9a30e86976210f5de176ea2b5e511d4e76ac4788", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "662781ddd4295000ba6e33c0", - "sourceDigest": "bb180d6849f2e6577343cf5c1e5ddc9922347d99decb6c666555e47b009cb49a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6628a675d4295000ba6e33d8", - "sourceDigest": "300d222f2b3f98841ad2f75e413cec71902167ad0e6decb191da287113f50d99", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "662e20c6d4511700f6885626", - "sourceDigest": "0171dffe6553dffee5333cd6177f2f419685dbc4130706c8f9e4618477bbb177", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "pivot-resize-indicator-group", - "verification": "getRowHeight on two indicator rows" - }, - { - "id": "6639d7dab19f5100ced6a692", - "sourceDigest": "4d0121ca5005cf5fa3855d0a14d152f55366f3982649c3f3c86e56c4f8a5a4b5", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [ - "line", - "scatter" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6639d9d4b19f5100ced6a694", - "sourceDigest": "f0a05722b3c1355351054ecfb4a05e49525533c68c67a1838186c5a309d69e98", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "autoFillHeight", - "widthMode", - "heightMode", - "cellType", - "indicatorsAsCol", - "markLine" - ], - "methodSignals": [], - "chartTypes": [ - "scatter" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "663b595f771bb200ac392804", - "sourceDigest": "7a7244ba1a85313ec4759401c868e8002d3523dce0d691d31716631de9607230", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCell", - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "663f393b0b3b8900c63a77f3", - "sourceDigest": "e4cf6b9b9fef364b43cd369660184fe04dd76a52db63be0c7106541eb6da4568", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6646c5abc18c8900b44d9a20", - "sourceDigest": "2f9ec53c4c0a3d96454506580cf608c5e84a610090f72092a32def462992ae4c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "664c61fdc18c8900b44d9aa4", - "sourceDigest": "2526ef8ea49435bc53925e03bd8fd36b1cb712aa0ced012d1511b69a4994b4da", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "664c6278c18c8900b44d9aa6", - "sourceDigest": "a36dce26c2dd1dbf9867b61cb5370d29000ad93f5b655e9ae20f66e949a9191a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "664f2b3ec18c8900b44d9aa9", - "sourceDigest": "f70359461f8c1aa550d410ad156e30e3333917bb86a96d45e22e9f77a98dfebf", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "indicatorsAsCol", - "legends", - "brush" - ], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "665548565a5b1400ab9139e5", - "sourceDigest": "652ad7277607366fafcde85131e856eb74d8626b87630fc034f08c198f518ba4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "665548c95a5b1400ab9139e6", - "sourceDigest": "67e025798777377759d81b06ea1011d0606b92ac67df2418cf8b00937a2ce145", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66554d5a5a5b1400ab9139ec", - "sourceDigest": "ca4c719a9f5062f6e20546e5a2681b601ccd43173ddefa53d88d1793e26084eb", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66557f20c18c8900b44d9ab0", - "sourceDigest": "c2d61c32e6cd9e62d831f5b75457bf34a306a758c17525a787f180dfb4b673b8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6655b8dac18c8900b44d9abb", - "sourceDigest": "8721d427c6451d0006ccdd365987c29b56ab55f7adae031d0bdff89b2ec9dc9e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "select", - "disableSelect" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6655b925c18c8900b44d9abd", - "sourceDigest": "2f3cbc7c0bef9ade283bba0f8f3b32fd56deefab0f85df95b780712bcd515c95", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "select", - "transpose" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6655b9bec18c8900b44d9abf", - "sourceDigest": "89fb0c809dcec12342da6c4f0f9ba9c351ab1fa875b96df5ccbcb19342917ce6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "dragHeaderMode", - "widthMode", - "heightMode", - "select", - "disableSelect", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6657de1e5a5b1400ab913a21", - "sourceDigest": "cd7fcb228ccc0ed9483d4cafdfbe5b5d3ef672557912d0783fc6c1c61c5f0748", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "665eb51cfaec2700ad74954a", - "sourceDigest": "af0dde6469423962525a595a17306954da5f001d069969b3f1cdfad25ee20e91", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-row", - "verification": "body/header click order + selected range + highlightScope + visual theme" - }, - { - "id": "665eb726faec2700ad74954d", - "sourceDigest": "822f02552ae69ca6ba53a0158722c1240f5482f59ef385de6b30b815e10e9f04", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-column", - "verification": "body/header click order + selected range + highlightScope + visual theme" - }, - { - "id": "665eb7fafaec2700ad749551", - "sourceDigest": "e8cb7d829fd0a7affeb7972abb774cc5b7f6204f55c0b0de2eff243c0d08a73c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-cross-theme", - "verification": "body/header click order + selected range + highlightScope + visual theme" - }, - { - "id": "665eba0ca4737f00b6623d44", - "sourceDigest": "2d6a1000241a832c9fa4736649c8e38cd1d736aed3f2e83507b6a61f5ee760ee", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-cross-header-cell", - "verification": "body/header click order + selected range + highlightScope + visual theme" - }, - { - "id": "665ecceafaec2700ad749556", - "sourceDigest": "cc041cf13f1b515995a547b8258d38b57cca6b06d6844fadd4379994f5acaeba", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "headerSelectMode", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-cross-transpose", - "verification": "body/header click order + selected range + highlightScope + visual theme" - }, - { - "id": "665ecf14faec2700ad749559", - "sourceDigest": "45f88bdfa79ba3c8194cb87c989197c73bba948e55bc2254e9b14eda295f8a8e", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCell", - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "665ed01efaec2700ad74955a", - "sourceDigest": "60556b67e241f85dcf4e18eddbdf0fb839b6e4f9f0bd4ff7fb1785e1b9fbe0fe", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "665ed0acfaec2700ad74955c", - "sourceDigest": "9e6662d2cba98cc0fa5158f6cf37851696b13ef0438ca2e4a8f696af55e0887c", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragOrder", - "widthMode", - "editor", - "rowSeriesNumber" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "665ed0fbfaec2700ad74955d", - "sourceDigest": "fd75dda4b958b7e64941f29258f0188fa06aa7932d4b4cc3f566093c3e2eb5b4", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragOrder", - "widthMode", - "editor", - "rowSeriesNumber", - "transpose" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66611f147ab71300c5d1e5b4", - "sourceDigest": "ad7c0129703dd616d8e57c505e2bd34bd2df693bbf85899f90c57326672ee1da", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6667bae37ab71300c5d1e5fc", - "sourceDigest": "ef8cb0eff6b96fbab7873e161d6c7d16ac34a966bf827b35fd80bc959b9899a2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6667c7097ab71300c5d1e602", - "sourceDigest": "51d13b60c79aee0075a88876edaafeab27ba0e4725f692926f6ecfff70bfafc9", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6667ce8a7ab71300c5d1e605", - "sourceDigest": "7166b744f2d437420385c6d177b36b607513293866b266668f3642e31eb436a2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6667f48f7ab71300c5d1e608", - "sourceDigest": "3454d602013a633cc2496956bb4a2b7be6ea3371c0c1b68efbf339a354987af7", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6667fed97ab71300c5d1e60a", - "sourceDigest": "a48fee51a7509e1a867f91d6b3a9c68e7f6f6ecb6b8f32280de4a13dd9804b2a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66681c3b7ab71300c5d1e613", - "sourceDigest": "67dc7ddd8320db90fcb492d2bb45e39155731bc0cb287444e40166ba6d1aae0f", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "frozenColCount" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6669078b7ab71300c5d1e615", - "sourceDigest": "0bcf6fc9b54a26bd45f993d0d1eee7688984b998c34f4b205ce830e91c47c5a5", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66690a707ab71300c5d1e617", - "sourceDigest": "6739ea903a2c7f9b5d331a47391c7c42293f3d7dca9292384a0ae744ef6c6924", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66690b2f7ab71300c5d1e618", - "sourceDigest": "ab2a567920c87fb4908a83bc6792cc5d5fece32f2f617e1b10a50db477cf0306", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66690c317ab71300c5d1e619", - "sourceDigest": "d835889072006c1cb355b0a0903a35b587eb5196c27f5afb35082213dd21b0a0", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66690cdd7ab71300c5d1e61a", - "sourceDigest": "13d81a9258c93760874b51d575d939c35fb3538774923c9687f059f48e89add1", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "666988d044759500c7c1c65b", - "sourceDigest": "2e7993333489ffe7c4d55201119fbb958627dcbd12d1ac08fdcd228c6c4d379f", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "updateOption" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "666a70ff44759500c7c1c65e", - "sourceDigest": "aad2cf3f27176e0ddb6a28b1b08c7c67f7bffdd7c32bda73d89fdecf6f5cdbda", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "sortRules", - "autoFillWidth", - "heightMode", - "customLayout" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "667281c871989000cfc6dc94", - "sourceDigest": "aa992b9638170a6f6ada3e5af3da1acf89bce368d5d38b5e82a48aba2b8a5fb0", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6672845271989000cfc6dc96", - "sourceDigest": "b9e65d629e3faac44db0b62ad7850c0e9007abf400f1b79efce745811b601817", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6672a8845338cc00af187b66", - "sourceDigest": "f7b18409e781106188341c2a66bdfa742081b1afe4cef3feaf08cff426c8c357", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rightFrozenColCount", - "bottomFrozenRowCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6672be3c5338cc00af187b67", - "sourceDigest": "3f04f391cce82a9e01b853e6a6a20eb3984c0c7d1b151d068a2e0588ecc8b8f5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6674f87d7726c300b462187c", - "sourceDigest": "b6793fb6b06a8751da8cedc719aaa4e86c6b517a4b3c9ba1b29591e334336b71", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "667a8a2af52eec00b51f2748", - "sourceDigest": "b942cc8bd5540510a45dfa6fa2fd3cadee6ab622d3cdf0cabb3d6d920d38094e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "667a8b12f52eec00b51f2749", - "sourceDigest": "cd27b2589df15b56b6630a27cbe4b18add4bc7c9eacdee8ef7b9d03c6f5e849f", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "667b93e2d8703200b4aca329", - "sourceDigest": "dbf434214ced75eb8be21e7242fdc950129c7894fc48338d3186c151ffa2f755", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "667be445d8703200b4aca362", - "sourceDigest": "f6d4271cca0d7c84f6c068b2d9ac9655caeb4bcd9dbcb6d1751ab2385ed44fd0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "sortState", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66800e739e4bad00ca1ae977", - "sourceDigest": "8af508aa050c96280a487a60419b3f24638f23759c0085497c26da90a44eeb22", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "editor", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66973fc327f96000ad549e85", - "sourceDigest": "37f3d806b41fdb2c4bc50525130eff262c7ff84beb1b7c6b24b4df12a6c65e56", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "669740df27f96000ad549e93", - "sourceDigest": "57a6353e7ff520bd398277e4a765ce6c1f969bf868e74d17ac0699a3b2532780", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "669a1adcd62b6300ba4720d4", - "sourceDigest": "ff0f4286ea21c5c1c31215f7d7124b2941953b465741198f18dc1c92d37ba894", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortRules", - "autoFillWidth", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66a09d4bd62b6300ba472129", - "sourceDigest": "c42d840953368bb59c2b899f5a4f5c1c282a16af2b6449d67f5edf07b58d3c22", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66a85ed477da4f00bdc525cb", - "sourceDigest": "81a9613643fb9224d97de5d195e650b264bc3a9991f904cb01c5794d192a147b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66b32f58aeb8a00109f2de06", - "sourceDigest": "30967ca9ece0a3a54b0f1302490afa9da83cf71fdb2ec5b1d11221fb2af7c863", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66b32fca632a0800b3e8a185", - "sourceDigest": "d76082acdf9f201c42ea552249ed34752895ac42576074658c5ee9e0dff2c047", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66b330096d307a00bc86797e", - "sourceDigest": "05b244c15c10caa93450ef8a60e88ce2ac1d7c265ecce0727481cb2150c10c2f", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66b331f2d62b6300ba4721d9", - "sourceDigest": "08aee6d3cf9a10d66d00fdc47db9f41ce93b52125b43a447538710829ccb064a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "transpose", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "common", - "line" - ], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66b58ed6a6fe1500c0461ae9", - "sourceDigest": "304dc76aefc10545d58a7e9f5f11340d892c49887bb0e33bcbe1c32bab6a1a6c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66b5c44f59051b00acb58ea9", - "sourceDigest": "a57dc1ee2d05715ee12140ee8a189be86f7ba89472eb8453466b34d1cda3ed86", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "fillHandle", - "widthMode", - "editor", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "rowSeriesNumber", - "select", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66b5e4aba6fe1500c0461b13", - "sourceDigest": "26a08085c0607cff68e9b55b33c32f5b40ada52cb250496a1e75cfc875852945", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "heightMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66c54e77c3ab4200c6b4fdf5", - "sourceDigest": "eff5f44b541eb21f986d4a510524b0b47064129d727ca7e7160ddb3585fc3692", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66c54ebdc3ab4200c6b4fdf6", - "sourceDigest": "ad8cf6bf6d25d8959d12dd8cca4567d5aa75fd03e7df2beef5df75082f793101", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "sortState", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "baseline_failure", - "priority": "P0", - "reason": "sortState is stored but the expected initial record order is unchanged on the official baseline" - }, - { - "id": "66cd48e95e11d900c8f0e956", - "sourceDigest": "9ce05e54b1edf5f7b3999ade305eb5d5398eaa088ea3804fac9d61b75b048903", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66cd7e4a5e11d900c8f0e967", - "sourceDigest": "aef3ca77adfaf08cc4c410aab76ca64d5f642257ec564e7f5eb6404c0b0eb180", - "family": "pivot-chart", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "autoFillHeight", - "widthMode", - "heightMode", - "cellType", - "indicatorsAsCol", - "markLine" - ], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "66cd835f5e11d900c8f0e96a", - "sourceDigest": "df6b7f31e59b119b057f0e8fbe8607fe32164c76b33b465cd6ac3f00b0c1998b", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66cd83fe5e11d900c8f0e96b", - "sourceDigest": "04c821d67ef23d979c5db9d188d92aa3dbb8dfc32273593bc31eb9f4fdc0e6fa", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortState", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "sort-initial-multiple-state", - "verification": "getCellValue + sortState" - }, - { - "id": "66cecb83b0f41c00c5324c87", - "sourceDigest": "ba7d20f5f7f54ce2f53b1fbe7d4c2be0e5470e3d961cedb9cdb008bdda66bf5c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66cefc08b0f41c00c5324c97", - "sourceDigest": "ea2e710b8c42f9238c3a89471e89e9f227280439ea875d36e26217ed62712128", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66cf13bfb0f41c00c5324c99", - "sourceDigest": "b0bb579766d411010a330c48b11d52b16907c9b9d6d867228c8fb79bdd74dd2e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66cf227db0f41c00c5324c9b", - "sourceDigest": "0ade7b5bfbf4eb8b98cad78949dd9e09fd63a804b3bb8e5f9f001adf08b206e6", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d17bd8b0f41c00c5324ca4", - "sourceDigest": "d88ee0ad2a2476d0a8f62be297e08d2dc69533921846b12f52f9365b95c742b6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d6c7f1178e6f00f99be0d4", - "sourceDigest": "fbd65f0b2a688e0b0e116bd10c3ff900ff65bca2ab6fe5176dde465b7e81a024", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 8, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d6d0b3f53b2e00f749f331", - "sourceDigest": "e86b5b57eb43b40591bdbdc93b9ef5bfff2315fa808c713075610764baa47092", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d81a31a892910101d39af3", - "sourceDigest": "3c2497cd0f5f249b2f331a8368b5d7acaafb51c4dff6c28d9cee009d18016d63", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d8266efd533a01263a0585", - "sourceDigest": "38eb2004fab799d96594534df8a98b2df6644c6525d6a5e8e6feb01536f30c41", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortRules", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d828b1fd533a01263a0588", - "sourceDigest": "859f65bf314654ed48fea1d4292ef904c0eab651fd2c0d80bf50aea35d102477", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d84b0d178e6f00f99be0eb", - "sourceDigest": "a5360b1173848ae753a2e540a07c29aa8837824955fdacae1cea82aebe98c739", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d84c44fd533a01263a058e", - "sourceDigest": "22a7f8673ba0057da1833dbce7a0da29f05c08479ccd9fd359e54c21be0db9b2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "sortRules", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d91d5afd533a01263a059a", - "sourceDigest": "add7a70da4dcd7a804d7ae0bbcad3ec439e17e2a582e1770d8482fcc40166310", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d95d69fd533a01263a05bf", - "sourceDigest": "49f965c9a00cb92d395008b1e4e116f2a7da93c2c39fdf80ab09d816c0a7e2d3", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66d971e60297dc00f7968894", - "sourceDigest": "131f09da78464cc63ebf719b9b05dd8971e71fe03c84a8a13c39c643cd582564", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d97ffe488bb800eba8cdb7", - "sourceDigest": "45ccc388e4b99f050f06d4091838115d94df6192dc0e364638f1a1c6d1ef40bd", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d99cd23c31b300f9c76235", - "sourceDigest": "4df7caadf162c6ae207b6e49a493f905eef93d1e82b4be86af1afbd7dcd924b2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "heightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d99d210eae0a00f267b3df", - "sourceDigest": "ca435f9d4e766c9b3fe4301a765d3e0f4ad4d44df33c86736ece2ea986236496", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "heightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d99d5872bb3f00f07a6e4c", - "sourceDigest": "48d516c574414a8cec244ecf410abde3a9874b53693c083dbf0663354b59361a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "heightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66d99d950846a700faef5dd9", - "sourceDigest": "9bc42dc9e1d6bc859e9b6cf5bb38db8b528aa02e099271295326bdf4335b5593", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "heightMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66da73450846a700faef5de5", - "sourceDigest": "df516d2fb537afc2aee686d1f06c6567396f622536d86d9dad2baf1c858fccf5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "pivotSortState", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66dad08152553d00fb0c9205", - "sourceDigest": "8e03b99936eb9092e7c173879d65a7ec405f5496c914e75a3fe5a10919d5e295", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66de62650846a700faef5e25", - "sourceDigest": "babcb785287df1287683f1c3f8e593dbc8521e3fe0b1a7cc73e61c078bac8bf4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66de93b00846a700faef5e3d", - "sourceDigest": "06b5fb21841480518ab159eb2ff3a8976e384e57e2914021c2eff126972083d7", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66deb2e30846a700faef5e57", - "sourceDigest": "798689b647bf4a8988d75e8d6187be442eea4583761b92b372fe7a344da8f248", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "widthMode", - "cellType" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66e42c6d0eae0a00f267b445", - "sourceDigest": "233aacf312ad66530d2fd511609db79fd599433f0056e659f5af6c76a60beec6", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66e42d350eae0a00f267b446", - "sourceDigest": "4cdeaa2a603c8517842b20add08d6ef1483a4ddfe363f2e28d64bd7bbf4468cc", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66e838f0e905a400f73269ec", - "sourceDigest": "2bbd9d4b856d0ed3c991b9bb6fc71d03f1c8db16aa52f0aebba922126ff82236", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66eaba5072bb3f00f07a6e68", - "sourceDigest": "bdae2e52f90cdec6433691357107200c5b70a1b692c46983e1ef8dda46fb718f", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66eb97f672bb3f00f07a6e7f", - "sourceDigest": "92bd3252c2575a081518b688a3b38eb2c62fe2c72e0a5c1abbf881e6b7dcfcf3", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66ed3e6e81adc800ee4b03a4", - "sourceDigest": "eb4b265ea256d289262893ae72478ecc0d0942a869e65e4b68258facf55d6a05", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecord", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66ed3ed53b27d700edcbbb95", - "sourceDigest": "44594d790a1c15291b45ce54dbc2c9b05b4702be23b45dfb80b457dab4dba606", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "addRecords", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66ed3f55488bb800eba8cddf", - "sourceDigest": "4119de6badfd2353e18736340ee344aa5c5c8b4cbfd3168f0088ac3a0878a168", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords", - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "66f504ee885776011c598a61", - "sourceDigest": "e6c666de3b35e911bed2e1c1260384d98496ae13f867bf815cb74322c304a989", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "66f689cd33c1e900bc71e36a", - "sourceDigest": "b1234b03904eb071f46c5b1f87fd47ce2fa82fa95a71423baef8f69c3bd3d953", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "checkbox-header-options", - "verification": "四种复选框列配置、七条状态数据与截图" - }, - { - "id": "6704cd0d22f17300a767a2be", - "sourceDigest": "02d81ea369c33f60aa52b75aa2fc24e40521c5d067ba3b20ab0dc61a2dbc03f0", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "autoFillHeight", - "widthMode", - "customMergeCell", - "customLayout", - "rightFrozenColCount", - "bottomFrozenRowCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6705f78a22f17300a767a2cd", - "sourceDigest": "6a077d6da6e5c4ce98ec3982868b2232689735a317d7c69527d0e3f70263688a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67066b9022f17300a767a2d8", - "sourceDigest": "2d8173a8d767cc4dd446374083e7882079c7f98424e046877b062506601d21db", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6708ede6241d7c00a693a15a", - "sourceDigest": "6726f41dc7f1e802b3af3a615958a93cb09f3296941540e89dd500ebdf642024", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6708f11e241d7c00a693a15b", - "sourceDigest": "7db916119185f4177f4a2b9887853b05aef5664fff5123588dcdf34cb09fd1b1", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6709e882a2b8c200b0bd6544", - "sourceDigest": "fdca62e0ebb7685a21d8b920a678c692f52f54e1947ac115b0d33434fd01ddc5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "671624efbb067d00b20cdc0a", - "sourceDigest": "7796d71cc107db22924fcabc066c0967171faa7b2e71912234cd357ee69951f1", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragOrder", - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67177444e4bb4400b299cab5", - "sourceDigest": "689bb68b4acfdc4d65dc6fae62dfeefd2fe4b08c7f52e0dff958efc073164595", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6718c4b6d7996f00b2b7c4d3", - "sourceDigest": "33f5327b48bf67f738ef47ae7ebf24522421b75df5da03cff205684b7f74f744", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "customLayout", - "frozenColCount", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67209e48e4bb4400b299cb47", - "sourceDigest": "e14ebef35aa7c204b28780e3cdc0906ae3a5e94299e9eb91cd4632a3cc1b9e87", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6721cafbe4bb4400b299cb4b", - "sourceDigest": "ceee9b498a7ebb658a34a2231a6aa74a73aa5f993fcf96d5e9c1cd1dec615aec", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "widthMode", - "cellType", - "frozenColCount", - "highlightMode", - "pagination" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67220c9ee4bb4400b299cb5c", - "sourceDigest": "d33d7daf23bb0ad269da5bbe97914ae2312c32da11848493f7802d6ec9cb05b3", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67247e1ddc57cb00bc3be948", - "sourceDigest": "7826030651d4d33cd8a296586b058a994a2e7c7e6c163f16b8df39a29daaac05", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "67247e9ce4bb4400b299cb86", - "sourceDigest": "c07c7d2ffa36c938fe79818024c52b91951dfc8d59aa14ce4428ba416628b117", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "editor" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "67249192e4bb4400b299cb8d", - "sourceDigest": "7a8672a916c10c608479dde5c85bd065656a78cc2b30ce80b7d8ac8e76658059", - "family": "pivot-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "autoFillWidth", - "cellType", - "editor" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "6729c737e4bb4400b299cbb0", - "sourceDigest": "67a7578ae72d3534be27a9b94dc69b9b83a336512c3dcadf72952cfdfa77696d", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "cellType" - ], - "methodSignals": [], - "chartTypes": [ - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6729c7b7e4bb4400b299cbb1", - "sourceDigest": "419b8f86839c46238de5a838f0f4eaeb9d13f112943e7e577ee5d36f431a2689", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "cellType" - ], - "methodSignals": [], - "chartTypes": [ - "common", - "line" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "672b5b0b71189400b2ec8d56", - "sourceDigest": "b84590b3d7ebe04bfaf5e21e69fe2290bfda18fa1d6d46dcf3c54b9da2fb4427", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "select-highlight-in-range", - "verification": "selected range spans header and body with highlightInRange" - }, - { - "id": "672c9d90e4bb4400b299cbd2", - "sourceDigest": "8cbf8568efe00d07963852e66c53061917f346c6f044bb7c4a2e731c9eae65eb", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 3, - "optionSignals": [ - "select", - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6731b2f3013a5500b2fe994d", - "sourceDigest": "e99b20d2e3a15bfdd99632ccdc76f06b295dde8b30de747ec68a37888fb4d6ca", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6731eb3f013a5500b2fe9961", - "sourceDigest": "af5dca9daa757f09e883b04b28db686a5b8b85ac0fe248e4e6b1f7a1fa869365", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "select", - "disableSelect", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6732f2e1013a5500b2fe9967", - "sourceDigest": "7c61ade475fbb96419f76f9a0e32673d150718173f1a94f9483627bbaf05e951", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "highlightMode" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6733203d013a5500b2fe997b", - "sourceDigest": "2dd417f03348da71f194bb65f2cae0be170f1da3a5ed1ebe1fe2379e003462f3", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 5, - "optionSignals": [ - "cellType", - "rightFrozenColCount", - "bottomFrozenRowCount", - "select", - "disableSelect", - "markLine" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67332c11013a5500b2fe9983", - "sourceDigest": "c6e5dbb8da7afe142e6267f8da33d4fca9021b05844ec5c5645e7c9a5d19b5a2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortState", - "autoFillHeight", - "widthMode", - "heightMode" - ], - "methodSignals": [ - "on", - "setRecordChildren" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6735c61c013a5500b2fe99bc", - "sourceDigest": "2d4023ff16f6440360a2bbda4dd910e0d1c28cbccd86df12e664b519fbaabdc7", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "cellType", - "select", - "indicatorsAsCol", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "673728e9013a5500b2fe99ca", - "sourceDigest": "696341ec2156c2dafc5d5dc5dca44011ece677dccc31156798c1124c659f2eac", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "drag-row-series-order", - "verification": "two row-series drags + record order + displayed order" - }, - { - "id": "673c5c17013a5500b2fe99e0", - "sourceDigest": "b7dc1f914eb4a4c84eb15f0f523aaa96ea5fadf167a5d8097fc4687b2640b200", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "673c5cad013a5500b2fe99e1", - "sourceDigest": "c533768e7169baa59d8915e99cc81568d59fc23e2cd5308a00447540d90368b4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-custom-compute-row-height", - "verification": "getRowHeight" - }, - { - "id": "673ece4c3a9fee00b29bd92f", - "sourceDigest": "1bdd55b5ca492f39737f59c7664b076feaad3ff2739d70cb9862547f952e963c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [ - "selectCell" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "673ee7133a9fee00b29bd934", - "sourceDigest": "c35ac001bc52610d63bcfa411ceb33e3223a0b6a9b688e7434f11acac5bff7d1", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6746dcfa71189400b2ec8dc2", - "sourceDigest": "a62292e0b44356bccd38c6d6e16f4fb95a28effead24160dd0a9e3abd734f405", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "cellType", - "frozenColCount", - "transpose", - "legends" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "scatter" - ], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6747e6693753cc00b3d7d303", - "sourceDigest": "72939438e5586d4aac27782b54d6daf5ae01c574dbd6de5c7fd0d3e22bf03065", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "widthMode", - "select", - "highlightMode" - ], - "methodSignals": [ - "selectCell", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67484cda71189400b2ec8dcd", - "sourceDigest": "5cc48b6ffd4dddc076795c6b7c3d48bf8f68c01cafe56b02aa8c35e7c3c6c2c9", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "widthMode", - "cellType", - "frozenColCount", - "highlightMode", - "pagination" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67497d4271189400b2ec8e00", - "sourceDigest": "28320c2b5f56462dd118e01d4f0dac7dfa199342bc86f0f3fd52af58d162985e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortState", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "675f9c36bb067d00b20cdcc1", - "sourceDigest": "d2c4bdf1e3bbe1a77861b7035ae0f71fe36a8f55577bf189add6baa5a050cfb8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6769255d86624500b106bd3b", - "sourceDigest": "ce5a4c08640aaaded15e52a4067ab6f970436f4a4526981e4c00488c17e6f3ac", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "getCellValue" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676a70de0982bf00b14e2316", - "sourceDigest": "5cb93df90be249057b812f05e19220af249c47404535e748fb38b8a2a84be350", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-indicator-hide-frozen", - "verification": "hidden indicator values and callback paths" - }, - { - "id": "676bb773df600200b24f54db", - "sourceDigest": "d544cdda39aa049ebe425eb41541fb3bd5bf7d1d1ecf245ade05b3b22d360465", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "676bb7bad2dacd00b3443e2c", - "sourceDigest": "d14c17346c3cdb0a820292c52dd9884913bf988273146ee1935046284492769a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676bbdfed350f600b2968c68", - "sourceDigest": "ea200739bd7041d47b9327c2112af30346034fcb6d6c8ae3138654268858819d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "heightMode", - "disableSelect" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676bc00e8e768100b114c2e7", - "sourceDigest": "07405940f2e54b2a034d51140476fe289f789a17a80b2bd2a6fc19b038fc61dc", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676bcd663e30ec00b2fffc17", - "sourceDigest": "25d7c0f9237860f27c467d94b351dab31343db0cbda4af77297f90a6a44d5790", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676bcdc554366a00b133b6be", - "sourceDigest": "874f7645229c794464e7b0e403108967a145d2e149bdf3d247f071f4ef017e8e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676e5dafb6ef7d00b00e8f37", - "sourceDigest": "1eb351a00e3674fe4d17b1274c2924b0fa3c22dd16bcdc0632b0fff4e80e1db5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rightFrozenColCount", - "bottomFrozenRowCount", - "highlightMode", - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676e65cfaf3eab00b23490e2", - "sourceDigest": "87d32e1505a299841f9f91c3bf11d42ed813fe5d287fca7f482c3bb499155da8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addRecord" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "676e6bc698804d00b1d620de", - "sourceDigest": "8db6496c8f90ee565ea139b0cd1c863efd9fb15d5f9ee41e43e3ce87fea4861c", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "dragHeaderMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "676e6d3820512600b3dfc3d0", - "sourceDigest": "751fe330b337d60e4ec9fa8faf3822ff38be6d455cbc6c2cc4591339e9319f0b", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "dragHeaderMode", - "frozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6777a053863ad000b1fc4055", - "sourceDigest": "b668048f5693ddad53d8e238a4e3d5b8e4e364fb0477c214bbc6f8bc5db0f435", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "showSort", - "sortState", - "widthMode" - ], - "methodSignals": [ - "on", - "setRecords", - "sort", - "updateRecords", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "677b78bf8e768100b114c37d", - "sourceDigest": "46f096c63bf149fd382b09c33cd46f66f3c53222d9fb93359eca0c81f48d6d3d", - "family": "pivot-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "677bb879df600200b24f5564", - "sourceDigest": "af7ccb621a4e8f5a6b6256af5bae9f2d73bef3e0da7833f347bfda53aa03aa2c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "678620838e768100b114c398", - "sourceDigest": "6e9479cf70e173af05d799ae91744509c712195a2fc245bfe13ffc5efd76acf4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-canvas-size-options", - "verification": "canvasWidth + canvasHeight" - }, - { - "id": "6786222198804d00b1d62177", - "sourceDigest": "7afa66b5c1da57957e610af9b7c4e47676ea230733d44146d11d9938f515268a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-canvas-size-options", - "verification": "canvasWidth + canvasHeight" - }, - { - "id": "67862349af3eab00b234917d", - "sourceDigest": "e2496f09ca146898447699d774d9dfb92aceaef0cbe3791932968aca98abe25d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-canvas-size-options", - "verification": "canvasWidth + canvasHeight" - }, - { - "id": "678624597020de00b01c0b49", - "sourceDigest": "7ef2c10d93c0816278f010f53aa40c50047c5fec837fc8f18bf69ae634df2ce2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords", - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "layout-canvas-size-options", - "verification": "canvasWidth + canvasHeight" - }, - { - "id": "6787a19f01916b00baea8448", - "sourceDigest": "39840f23a08df931d48c6a8834cb2cc63fd10a50c57c586ab8a4dd5073c92386", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "addRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6787a5e7d350f600b2968cfa", - "sourceDigest": "8eec0c062ec24abe2c55494d1df2521ebf22b49e65bb6bd588cdef98fb3c40af", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "deleteRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6787a715af3eab00b2349184", - "sourceDigest": "9d14883ead7828a3eebf16d175241c6ddd98f90cfb93db4a90f9c00663f332c6", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6787aea5863ad000b1fc4082", - "sourceDigest": "7280a6096c5d499bca7f0997a184332ad533b78535d87b14b64b81af7cd95e67", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragOrder", - "widthMode", - "cellType", - "rowSeriesNumber", - "groupBy" - ], - "methodSignals": [ - "updateRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "679b5bae03fdbc00b04b20db", - "sourceDigest": "4d972fa2369f1ec5dfdda3ac67ed45ff943f1b8b4a115e66f369ccf3b4377d6d", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "679b5d395091f000b1aa56cd", - "sourceDigest": "633201cc78d21d530234ce8540df616eb925602661009440b0e4b89b88b78ddc", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "columnHierarchyType", - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67a4a0327c7ae300b1a48b54", - "sourceDigest": "f961c86309ed18ad6d6ec1f89ddf56480b10bc7b4d3911d97212b3a09c5b9b8f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67ac19437745ab00b1614f0a", - "sourceDigest": "4370fd7bac2252b760fdc9b728e74240730e730664f67f16bf2feba9beff50de", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67ad93987745ab00b1614f0c", - "sourceDigest": "e6710e08ec0ca684adb37cbfe8d06b1c5a4849b3e46a2566619baa6724628200", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67ad96ba773c4000bdf99d61", - "sourceDigest": "fe88c646c3c7a6934281d41e7083c6af0e98fb801c15d445148d9b4b9731749f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "transpose" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67b47421c1cefe00bc77fb71", - "sourceDigest": "ecc4c0ca46805945ef36e823a3cab29dfcfcfaf5987a548a9d3fe82f092d1ef9", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "67c563535f787500b2874704", - "sourceDigest": "681f80a1d58e34b2367cc4ac8ae6368819c58377bc152b71e483c7cf36d7178a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "sortRules", - "sortByIndicator", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67ca9c6cae681000a7b22eaf", - "sourceDigest": "b1d8d66e7b0685468300a13be39d95311d9edb84f6e99da0b9f5feb235d4c09d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "sortState", - "dragHeaderMode", - "dragOrder", - "widthMode", - "rowSeriesNumber" - ], - "methodSignals": [ - "on", - "setRecordChildren" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67cea3ea06d94f00a8e3a6a2", - "sourceDigest": "dc54fafa4246e63971b1fbfaa10c0102952aedb746f2317ca6863cbef00ff885", - "family": "list-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "67cea5077e106d00a74f27dc", - "sourceDigest": "b17dbfee6e3d20a9e507cf418897a375016d188fbeb640f7768d3ee5a0520b9a", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "showSort", - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [ - "on", - "updatePivotSortState" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67d00aa7dc8abb00a7c081b9", - "sourceDigest": "89ca32bdbfd5a085977fad6f06c94909a59f06d4e47b2b331fc7f5e381aa5d96", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "rowExpandLevel", - "showSort", - "widthMode", - "heightMode", - "cellType", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67d7c346b8637b00a7a32251", - "sourceDigest": "503b32423243a84dfe8949762e6037e59ecd238fe5d39f2a8e2d9d2b0eae8d5e", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67ea804057046200a70ed549", - "sourceDigest": "29e790154d0222d74d02670211f0afb9be7900fe57809d44f432a91a59181bd8", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "pie" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "67eb9c2ab8637b00a7a32277", - "sourceDigest": "77f22af381369b79d0fcc6e335e5b9129442d231947f38f89b7bd14aab37654c", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67eb9c5528b4c200a9da9963", - "sourceDigest": "c1612b17c50029cded0a0330e6b6ada3d70db59b8580312bbb8dc6170d30857e", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67eba04b7e106d00a74f281d", - "sourceDigest": "fa1ae1b92622425495f9758f7d7c2a99b9406262e7e050dcc4622b5efee4f341", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "67eba18063ae2300a3122147", - "sourceDigest": "8b602cf038b7b45578f11568a6724d5fdc1ef0f06ef392bac8a394e08628e1e8", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-corner-remaining-variants", - "verification": "rowCount + colCount + canvas.width" - }, - { - "id": "67eba1e52ef4e200a7775a9c", - "sourceDigest": "0644670fe7aad27dbf78acfdcb2ca683bf36e31dc69265028d97bd92214bc6e5", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-corner-remaining-variants", - "verification": "rowCount + colCount + canvas.width" - }, - { - "id": "67ebb661b17ad700a78185fd", - "sourceDigest": "1aece69bcccc31edba88421c2551a69d166298ee5114742ae5b4cdfcf4e71d1b", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "dragHeaderMode", - "autoFillHeight", - "widthMode", - "customMergeCell", - "customLayout", - "rightFrozenColCount", - "bottomFrozenRowCount", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67ecf4e1d4307700b694535e", - "sourceDigest": "b09df7c5083e64d98fe5d3ab2785bfa3309bd310f0e8e1110ad4dd925376414d", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-corner-remaining-variants", - "verification": "rowCount + colCount + canvas.width" - }, - { - "id": "67ee3c68f6d6fd00a872e89d", - "sourceDigest": "65ce5b971da228a3c99a5ad98284dd2bf985247afce6493198e19feee206d16c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67ee42fdd3963500b3ec8266", - "sourceDigest": "5132c7e0716c1187b2dafe10d02928de61cdd737ea7a05d656d845323739d551", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber", - "select", - "headerSelectMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "67f37130dc8abb00a7c08200", - "sourceDigest": "942a038c58e3eff342c2a94a7a12a306669fc650c4c15dad21c20d9a57549a1a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "widthMode", - "heightMode", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "680616a22b0c7600a7633ca6", - "sourceDigest": "3b1ba5e8cbe3140bbcb1b6d83fdacc2c4f09000d1dbd63b248b7fed9f9a32ac5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "681c2a5ab01ec400a9952511", - "sourceDigest": "f3b268d14ffa68a31ff33810bc31ca79f670e17500f618d17c8604821a6aff7d", - "family": "gantt", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "cellType", - "frozenColCount", - "moveable", - "markLine" - ], - "methodSignals": [ - "release" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business process information; source is not copied into the repository" - }, - { - "id": "681c859484849700a73864dc", - "sourceDigest": "dbb213f09b82b29be11fbbc865022633a85b4118bfdcdcd409645d4f123b2a50", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "heightMode", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6825cf222af66800a8883eec", - "sourceDigest": "05bf2e58f47749719b09ffadac6d17d20a82559578f75dcf3fc02d96a6427216", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 4, - "optionSignals": [ - "sortState", - "autoFillHeight", - "widthMode", - "heightMode", - "cellType", - "select" - ], - "methodSignals": [ - "on", - "setRecordChildren" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "682af6dd9736b600a9c14d2d", - "sourceDigest": "e1e371b54b07bac879ac21ecfa4d0713236286ab96ac728a00c21f3a45af5b37", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 3, - "optionSignals": [ - "dragOrder", - "widthMode", - "cellType", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "68355f7a85125600a8d8d2f5", - "sourceDigest": "619abf86480a613c3c91a890da0400547c00f2cc48eab47a0b13d344e3ef34e0", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6835816bea3ac100a6de076c", - "sourceDigest": "4c5e0cb797e7cd7a24e6316d9c1db43c09e008adf85d2066eebc990415f210cd", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragOrder", - "widthMode", - "cellType", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "68381438ff077e00b3999c17", - "sourceDigest": "42708e471267be824187d77ac2bd7066b17860939340f86663026f7e5486522a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [ - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "683ea8ae83f5b200a644bb88", - "sourceDigest": "88235b1705306a387332127076b52e3845915a788a1a3b0864dab2967a60a15f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "sortState", - "dragHeaderMode", - "heightMode", - "frozenColCount", - "bottomFrozenRowCount", - "groupBy" - ], - "methodSignals": [ - "updateFilterRules" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "683eae5f95606700b42ea9f8", - "sourceDigest": "5864704197761d197d1f268b48fccd2922c3908f8581e12e0bc467ee7d8291a6", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "684bf16d0ff98d00a8ab8422", - "sourceDigest": "c955621bc34848ce1bd05dd26ec34720a0ed3c8e0fa49f44944ba1f1418e41bc", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "on", - "updateColumns" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "68551e92ec174500a64d7506", - "sourceDigest": "e31c39a6a12eda8978ae8efd5bb69b85d8bcc864c77fcf891c7f896dadcf00a5", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "685a21522d188e00a8fe63f5", - "sourceDigest": "8b20f57934ca821fd80e276ed1c29342233f733d5d7cd88972bbaed27d935296", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode" - ], - "methodSignals": [ - "updateColumns" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "685a47007e0fca00a71f22fe", - "sourceDigest": "adc2cc8872cac32b76dc7650d340962c9890bc83287c46f60c9dcbc6a069d783", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "groupBy" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6863aa8484406200a7ab3d49", - "sourceDigest": "de5fce5d9aee54264ac45f92a5b8debc48e9b8b327cefa5659f7ca30baa35444", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "heightMode", - "frozenColCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "688752cafce3b700a79389e0", - "sourceDigest": "4cf59735a119faed16655c086dff6558f0fd7a9e21d8b2dfbaa0c303f78aa106", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "sortState", - "dragOrder", - "autoFillHeight", - "widthMode", - "heightMode", - "cellType", - "rowSeriesNumber", - "select" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6890669a8af47900b375bcd0", - "sourceDigest": "460a84110c70d912b2e5c6de165716e1efcd2fae7a4c71253d95c5b5ad2eab4f", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "689af7926dc79400a6bdb7d9", - "sourceDigest": "acbc07ab37d9617efbc52c78bace8567916a62a4d28ea5d3d734e3aba2ddf49a", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "689af908bcd29200a74f09b6", - "sourceDigest": "411160fc22ba4593c006c5c909048c8a078fc4ad5b3ba88f1e6ed5566e91a9aa", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "frozenColCount", - "highlightMode" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "68a2e109fcb96500a7134dd7", - "sourceDigest": "bd1d2b2b6600859ddbb41157d1f3ce086d65c5597dd10616c6a6291709340ccc", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "frozenColCount" - ], - "methodSignals": [ - "setRecords", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "scrollbar-ignore-frozen", - "verification": "动态冻结、setScrollLeft 后主滚动条宽度与截图" - }, - { - "id": "68b012cb8af47900b375bce6", - "sourceDigest": "5fb5b408c0dc1ae463696f306c6793449b58a55c4ec4d316e4e2ff94cb982bf7", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "68c141a407d0a000a8414c22", - "sourceDigest": "c3ee2d5be2457ac537945cdd1a6cffd8ae696d68f67dac7e2d77bc1e242a0160", - "family": "list-table", - "sourceBucket": "needs_resource_review", - "recordedInteractions": 1, - "optionSignals": [ - "showSort", - "fillHandle", - "widthMode", - "editor", - "frozenColCount", - "rowSeriesNumber", - "select" - ], - "methodSignals": [ - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_resource", - "priority": "P2", - "reason": "replace the external resource with a deterministic local asset before claiming coverage" - }, - { - "id": "68c28041711d9200a827cd52", - "sourceDigest": "d35fe10724bf45a3a8cb1e1facd70fd2884adcb64cf77e2e63db44ea0f7148f1", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "68cb7c2e022f2e00a798882c", - "sourceDigest": "7672de6eea9cecd929a59f94159fd748f30f8913ffd5ea275d267096c9c2a00b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "heightMode", - "cellType", - "indicatorsAsCol", - "legends" - ], - "methodSignals": [ - "on", - "updateFilterRules" - ], - "chartTypes": [ - "heatmap" - ], - "actionKinds": [ - "drag" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "68d5fd759b3d3c00aca4fa1d", - "sourceDigest": "bd3cfbedbd0cb5c4b2f0d2a3df6beca570b1512758aafcb1ecb8c291221398ff", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "dragOrder", - "widthMode", - "rowSeriesNumber", - "highlightMode", - "pagination" - ], - "methodSignals": [ - "selectCells", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [ - "drag" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "68da2815ea187f00a7eeecab", - "sourceDigest": "d9889e9006e1eb8e579e745b75926127352d2580adefa089b957f6006b69d735", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "dragOrder", - "rowSeriesNumber" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains business-like fields or values; source is not copied into the repository" - }, - { - "id": "68da2cb2479d9000abdefad4", - "sourceDigest": "81759f9d92ef9c3a9e103aa01f3fdf546e5dd8face87b44a259d38521f98e674", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "68da631f98ac3600a8a21cb0", - "sourceDigest": "e67233b24f64b0274b3444b3968208bee35c6b48dcd7a045a85a461ea48079b2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "groupBy" - ], - "methodSignals": [ - "release" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "privacy_excluded", - "priority": null, - "reason": "source contains customer/order identifiers and product-level business records; source is excluded; no source-ID linkage to local cases" - }, - { - "id": "68ff1d7f07d0a000a8414c50", - "sourceDigest": "39337694788549c9c480a2c3b6caed6c4f68b088dcf61373ca563b481ab9d46d", - "family": "sheet", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addColumns", - "changeCellValue", - "getCellValue", - "release", - "setCellContent" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "sheet-insert-columns-before-second", - "verification": "公式结果、列数和第二列前插入后的数值位置" - }, - { - "id": "68ff1e7c479d9000abdefaf9", - "sourceDigest": "8ea3fef006f4c9dd005502cf38aa0b817329a05e06c9ec1611a68a487737114a", - "family": "sheet", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addColumns", - "changeCellValue", - "getCellValue", - "release", - "setCellContent" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "sheet-insert-columns-before-third", - "verification": "公式结果、列数和第三列前插入后的数值位置" - }, - { - "id": "68ff243743ec0700a96ec5b8", - "sourceDigest": "1b7bc8dffdeb5be015418c19c741081aef0ecea7be03e0b4900a4e22d54ef70f", - "family": "sheet", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addRecords", - "changeCellValue", - "getCellValue", - "release", - "setCellContent" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "sheet-insert-rows-at-start", - "verification": "公式结果、行数和首条记录前插入后的数值位置" - }, - { - "id": "6915877abea5bb00a82e33e3", - "sourceDigest": "9fdd2b1b8caa40a8acebaea53d02ff3c0f6e8265b3f15c52b5c0d20f9df3513b", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6916e90973443000b25cf383", - "sourceDigest": "143df592c6628a05c718298f122469b48c05f0b4401c6e600539cf9ab7dd24a4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [ - "cellType", - "indicatorsAsCol", - "chartDimensionLinkage" - ], - "methodSignals": [], - "chartTypes": [ - "line", - "scatter" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691ae62a9fa5bc00a804fd0c", - "sourceDigest": "226ea2c65bff1100013db7661b0a6eeb42bfb7540767a1385c4ba16ccb676bf4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "area", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691bdb5fd51cdf005f9518b9", - "sourceDigest": "115574a2d96e3b6668270abbc789074492cc895c00c492f69b0125544fca963f", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "area", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691bdc626d5962005ddf928f", - "sourceDigest": "b4d0d3669d5c6f3efb5943e2abcb2e048b0e4f6dd22f5efc29619209c5dd86b4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691be2fdac45d5005c73eeb5", - "sourceDigest": "8a348277cbe839b8a2c82de228daacaaf3a60d34859071d1ebe1ed7982db5cdc", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691be5806d5962005ddf9290", - "sourceDigest": "5d9e39030c6f922b5b0401d535393d38c00327bd4439ea987561914d8a669619", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 3, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691be61103bd9b005bd0d506", - "sourceDigest": "14c8fc93d9a74fcb6031138d29aa69cc64a3911b435d049533a01b8ae01fc63e", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 4, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691be68b99e1ad005c651788", - "sourceDigest": "a530a11d741c86712bf8a59ce36780bd46bef7f1a4be93b6cea80b3e076330fb", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line", - "scatter" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691be7ba6d5962005ddf9291", - "sourceDigest": "976ed725a40be5c859a4ce20e409593ed5f1e86a45c476b5d9031a0ed3c675ec", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "pie" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "691fe2f6cfcfbb005cb0452c", - "sourceDigest": "045d8f4e35cfafeadf14db72eaee1a4bd9184dbfb11d5eb29815231ab4d857aa", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "boxplot" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "691fe393215128005c991a94", - "sourceDigest": "9be2efb5402220e3bbca0825675eeed09f704e1a0626c7ea099b5643636545f4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 2, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "histogram", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "691fe3e96d5962005ddf929d", - "sourceDigest": "b5ca442a00ba80f661048a1d2bac68ccccd18f3af7920839086a5723c40df24a", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line", - "scatter" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "692914e31b77b1006634e812", - "sourceDigest": "edca627d148c4c86aca8dd61e7018ab4972eba023781edee5001cbdaff2ef6b1", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "autoFillWidth", - "autoFillHeight", - "widthMode", - "heightMode", - "cellType", - "select", - "headerSelectMode", - "highlightMode", - "indicatorsAsCol", - "legends", - "chartDimensionLinkage" - ], - "methodSignals": [], - "chartTypes": [ - "line", - "scatter" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69292cda9995e4005d1533c2", - "sourceDigest": "b8cc6ba3a8b838a29feec894ded86c7511328a030c20760babe855247600459d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "editor" - ], - "methodSignals": [ - "selectCells" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "plugin-excel-delete-range", - "verification": "Delete clears selected editable range only" - }, - { - "id": "692d599f94f4f800664fe7a5", - "sourceDigest": "c3b02070addb4dfade08f2f83bc2e699eb6005bffeeb647ec71badafd37591d2", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6931392fc2ba7a00667c9f7a", - "sourceDigest": "f9d1d94c0e098545f2e6ea8ffc083dc3968687cb6f5840b400fb129ba23775b1", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "boxplot" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69368363b0351700666bd27d", - "sourceDigest": "2668426d48bc67c014411731aae4efe356fcd0110793060f06b2395cb6b4b471", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "histogram" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "693b9f82065e8a005c9c62a3", - "sourceDigest": "3781abb3ae8df19115cfe41fe5eda5c7a67fa9059a770b4abbc53b2685d503fd", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "rowHierarchyType", - "rowExpandLevel", - "widthMode", - "heightMode", - "cellType", - "frozenColCount", - "rowSeriesNumber", - "select" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6942732a862ee80066b9cc4b", - "sourceDigest": "bc717ccdadcd0b39df9b0f9b6636b80fdaadc2af1657c9d946eacb522100a734", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [ - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6944fa18d64f80005dcf0f6e", - "sourceDigest": "4d8076bf40d550561a2e29cf97871a17ba5e9fbf61ee075296377999b7ebc382", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6944fa783a0a25005c12ceff", - "sourceDigest": "d37ac176a22a3808b4e4a105b8da1ede72e7a157b020fb7da7527df9ff3f2cca", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar", - "common", - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6944faf3b0351700666bd297", - "sourceDigest": "9d9bab51423e04f8f65d01e70f5c21cff8d7f19ff2c1bf37549bfce28df4dfa5", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "cellType", - "indicatorsAsCol" - ], - "methodSignals": [], - "chartTypes": [ - "area", - "bar", - "common", - "line", - "pie" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6948e4bce92471006708ec4b", - "sourceDigest": "b16fb748158520a0cc559dbbe90a42a1674fdbaf2ba01392a9347b81519167dd", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69532d5356fc63005df9d064", - "sourceDigest": "408b8a3dc46dbca17d71c462055d29f60e8c8c2393e119213248a24295aa2a3b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 4, - "optionSignals": [ - "indicatorsAsCol", - "brush" - ], - "methodSignals": [], - "chartTypes": [ - "bar", - "common" - ], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69533c23ba859d005d8eec1f", - "sourceDigest": "b3e726a5f68bba94ebb24ea80e497d9b95a6d12bb9754cde8f43404ad6b69fe0", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "chartDimensionLinkage" - ], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "695347df862ee80066b9cc60", - "sourceDigest": "acfc529d61aeb576f686226f027f80b6d58335df761c2896840595c53722b1e4", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "rose" - ], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-chart-rose-indicator-title", - "verification": "rose chart cell and rendered screenshot" - }, - { - "id": "6954de338ff7e3005dfc6526", - "sourceDigest": "88c05d2397359a269736ada4aaa41bb422472ba214dac7ac62bff8348dcf0933", - "family": "pivot-chart", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "chartDimensionLinkage", - "selectedStateFilter" - ], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "pivot-chart-brush-multiple-selection", - "verification": "chart brush drag triggers brushEnd" - }, - { - "id": "696739d9b71f44005d359b67", - "sourceDigest": "80bc7f27621d9f7db36f63210a002e563c1a39f8d09ab5dbde19aeda38781ce7", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "click", - "drag", - "move" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6968ba3844e1cd005ed63372", - "sourceDigest": "2f3e1cfc0b47280986b78cbd10165305c9f55a046c335c21637174a68a96a76b", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [ - "click", - "drag" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6969eb738ff7e3005dfc653a", - "sourceDigest": "821b384217c80cb190228ef3558b9b3796fc0021df92a4eec5ac2014a59d7345", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "deleteRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6969ecde09038a005df130aa", - "sourceDigest": "0467ac1b95d5008579cea6cdefdbde1c96ffeb278977eaa4f7abb8af8696eba4", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "deleteRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "696f370392fe0b0067317511", - "sourceDigest": "6660816a22798ea565fbaad556338f8c034bc8e6c9ff5b482d62cf2480f36f81", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69787c4d96d5c1006802a2b9", - "sourceDigest": "a93a784a4b26429579a07175655debb5ad28369656a1a9306ac2236490a25b71", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "rowHierarchyType", - "widthMode", - "editor", - "indicatorsAsCol" - ], - "methodSignals": [ - "changeCellValue" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6979f44b20f246006732267e", - "sourceDigest": "b94a39e1dddaeffda683b6401240c7884e54e1ceafd7bcf05ad98fb1498376f7", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "legends" - ], - "methodSignals": [ - "on" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "pivot-color-legend-order", - "verification": "visible legend bounds and top layout" - }, - { - "id": "697f0e81cfeff4005eb02fa4", - "sourceDigest": "37a85932e8b25705973f6df515f0d932e66efb259d534d315c674dc6f887f8fb", - "family": "pivot-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "showSort", - "legends" - ], - "methodSignals": [ - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "69819e57c4422900689313aa", - "sourceDigest": "ce638d7a068801e6b67f32c325f8fa098c4a1a3a2bfa059780f4dd3fc5422a04", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [ - "dragHeaderMode", - "widthMode", - "heightMode", - "cellType", - "select", - "disableSelect", - "indicatorsAsCol", - "legends" - ], - "methodSignals": [ - "on" - ], - "chartTypes": [ - "bar" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6982e5a97a558400611ce04b", - "sourceDigest": "184e7dfdc42ea006aa33accb2ceb0755f1c985ba03f3ea42f7ec38bb3d83081d", - "family": "sheet", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "addRecords", - "changeCellValue", - "getCellValue", - "release", - "setCellContent" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "sheet-insert-rows-after-first", - "verification": "公式结果、行数和第二条记录前插入后的数值位置" - }, - { - "id": "69899af7657c7a005c098ad8", - "sourceDigest": "d60d6adf34a3d6cd94e04b2849436a1deab38c8a499773fa73573b0aaebf8138", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "circlepacking" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69a6c05d547bee005d6c847b", - "sourceDigest": "9098bfe3b595d4f3ebb318bc7d7533f6310c17ba545de6d088dc432caff3e64f", - "family": "pivot-chart", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [], - "chartTypes": [ - "line" - ], - "actionKinds": [], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "69c23daa709fdc006857f1c8", - "sourceDigest": "61ca69dc7d768cd22c1b8270e841ee9ab376a4bdeab0ee926ae029339951e6fe", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "frozen-scroll-columns", - "verification": "frozenHorizontalBarPos + rightFrozenHorizontalBarPos" - }, - { - "id": "69d614f2e41b43005d89a624", - "sourceDigest": "aa5d52c34644c5012f725b6444a7ffef432a2d4a0fd3a783241279dd70ff4c54", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "headerHierarchyType", - "headerExpandLevel", - "fillHandle", - "widthMode" - ], - "methodSignals": [], - "chartTypes": [], - "actionKinds": [ - "click", - "drag" - ], - "status": "migrated", - "priority": null, - "localCase": "plugin-auto-fill-grid-tree-origin-value", - "verification": "fill-handle drag and copy-fill changes target cell value" - }, - { - "id": "6a1416f2709fdc006857f1dc", - "sourceDigest": "d10cb860c5db798b01a81c86e9d47c2efaa5b4a3ef3db104b8aa7cc0b96227e9", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "widthMode", - "heightMode", - "select", - "headerSelectMode", - "highlightMode" - ], - "methodSignals": [ - "selectCell", - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "select-header-scroll-top", - "verification": "header selection and scrollTop after click" - }, - { - "id": "6a68957b3dd664005e729649", - "sourceDigest": "50cf110bf7ca31165743a1cdedb29acaa341c5b1987f1f559752cc24ce3f0f0f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 2, - "optionSignals": [ - "cellType" - ], - "methodSignals": [ - "getCheckboxState", - "on", - "release" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "tree-checkbox-record-index-clear", - "verification": "checkedState" - }, - { - "id": "6a69af4d02c575005f77ab2c", - "sourceDigest": "cdc21462d11630f0367d47d38dc98dbc62da53a1f191abb51668033c1b78b900", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode" - ], - "methodSignals": [ - "release", - "updateOption" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "tree-zero-height-toggle", - "verification": "getRowHeight + renderedHeight" - }, - { - "id": "6a69f6177406d0005d72f226", - "sourceDigest": "92064e6744d9516d5be4ba77b9ec748dc84887f1e578007c613a188675122caa", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "bottomFrozenRowCount" - ], - "methodSignals": [ - "release", - "setRecords" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6a6af1ccbfb525005fed69dc", - "sourceDigest": "b39f1bb4798f2b8bb21527f773d3888cd44a042415fa986a28adeaaac1af298d", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [], - "methodSignals": [ - "release", - "updateSortState" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6a82f7a71d0efd005e397e9d", - "sourceDigest": "33a1aa5a5eae772a3f7e43cb69109a622e702e3607d54add81b94ac756daca07", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "cellType", - "frozenColCount", - "rightFrozenColCount", - "bottomFrozenRowCount", - "rowSeriesNumber" - ], - "methodSignals": [ - "on", - "setRecords", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "migrated", - "priority": null, - "localCase": "frozen-empty-records-header", - "verification": "311 列末端点击清空记录后左右冻结表头与截图" - }, - { - "id": "6a8597d0a44900005e2b8e47", - "sourceDigest": "76a134f6859a94ec067736abfa5346b83eff832bef5b44e7a148cff0f3c4b7a8", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "heightMode", - "cellType" - ], - "methodSignals": [ - "release", - "setScrollTop" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "link-merged-auto-height", - "verification": "link type, merged range, no navigation" - }, - { - "id": "6a8c044f1d0efd005e397e9f", - "sourceDigest": "089395b7afdf31425e3f72179af5b3ad73c7c5c825261cca94a9a37be4f07c4f", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "editor" - ], - "methodSignals": [ - "getCellValue", - "release", - "selectCell" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6a8c044fe9ec270069f957ea", - "sourceDigest": "aef0f9c3de5b824692db3ecfc5fd385bd985f2a2e4909b66b9073a3c158c2f67", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "editor" - ], - "methodSignals": [ - "getCellOriginValue", - "getCellValue", - "release", - "selectCell", - "selectCells" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_interaction", - "priority": "P1", - "reason": "recorded actions have no proven matching local action and assertion" - }, - { - "id": "6aa3b008d1dbbb005e7d9500", - "sourceDigest": "98c52656101af16155b4120b2ed50275ac791fe579894a2508a6b15948fcc172", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode" - ], - "methodSignals": [ - "changeCellValue", - "getCellValue", - "release" - ], - "chartTypes": [], - "actionKinds": [], - "status": "deferred_static", - "priority": "P2", - "reason": "configuration or data variant has no proven matching local assertion" - }, - { - "id": "6aaa79209c5d40005e364d42", - "sourceDigest": "d90fb5e87cd766240595562b2f81d63d291c8f3d5543b48a08ce27a4bf9bb3d7", - "family": "list-table", - "sourceBucket": "needs_complex_source_review", - "recordedInteractions": 1, - "optionSignals": [ - "heightMode" - ], - "methodSignals": [ - "changeCellValue", - "on", - "release" - ], - "chartTypes": [], - "actionKinds": [ - "click" - ], - "status": "deferred_large_source", - "priority": "P2", - "reason": "reduce the large source to a sanitized minimal fixture and verify its unique behavior" - }, - { - "id": "6aaba81349fc4f005c341b4c", - "sourceDigest": "7e293d685765164cca2aaea50799d20093ee0d06796fef6cc1abf91c84ed5119", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 1, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount" - ], - "methodSignals": [ - "release", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [ - "click", - "move" - ], - "status": "migrated", - "priority": null, - "localCase": "frozen-shadow-start", - "verification": "横向滚动动作后回到起点;左右阴影可见性与截图" - }, - { - "id": "6aaba81349fc4f005c341b4d", - "sourceDigest": "5e49311ed620fb8594ed23059c791de560deb9a556bc5b8df41a2796bf669d4c", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount" - ], - "methodSignals": [ - "release", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "frozen-shadow-end", - "verification": "setScrollLeft 到终点;左右阴影可见性与截图" - }, - { - "id": "6aaba8136d3a95005dc7fa6e", - "sourceDigest": "9549a4eca5c1069aa68af878d0a93062eaf35cd0c0fdad03712bbb14e6b11bb2", - "family": "list-table", - "sourceBucket": "public_candidate", - "recordedInteractions": 0, - "optionSignals": [ - "widthMode", - "frozenColCount", - "rightFrozenColCount" - ], - "methodSignals": [ - "release", - "setScrollLeft" - ], - "chartTypes": [], - "actionKinds": [], - "status": "migrated", - "priority": null, - "localCase": "frozen-shadow-middle", - "verification": "setScrollLeft 到中间;左右阴影可见性与截图" - } - ] -} diff --git a/packages/vtable/__tests__/visual/cases/COVERAGE.md b/packages/vtable/__tests__/visual/cases/COVERAGE.md index 719b206499..282ad24f36 100644 --- a/packages/vtable/__tests__/visual/cases/COVERAGE.md +++ b/packages/vtable/__tests__/visual/cases/COVERAGE.md @@ -1,47 +1,20 @@ -# 本地视觉用例覆盖 +# VTable 本地视觉覆盖 -当前有 204 个本地用例,关联 227 个真实 BugServer case ID。本清单描述实际验证目的,具体 ID 用 `--list` 查询。一个视觉用例只代表所写的固定输入、动作和断言;不能据此推断相邻配置或所有 BugServer 用例已覆盖。 +[`index.mjs`](./index.mjs) 是唯一可执行清单;在仓库根目录运行 `node packages/vtable/scripts/visual-test.mjs --list` 可查看所有用例的 ID、目的和路径。每个用例只验证其固定输入、动作与断言,不能代表相邻配置或 BugServer 全部用例都已覆盖。 -| 功能 | 当前代表用例 | 主要条件 | -| --- | --- | --- | -| 列表与表头 | `list-basic`、`level-span`、`header-hidden-nested`、`header-hidden-parent`、`header-grid-tree`、`header-grid-tree-transpose`、`header-grid-tree-filter-expand`、`row-series-number` | 基础列表、多层及 grid-tree 表头、隐藏父子节点、筛选插件下的表头展开、序号 | -| 单元格与样式 | `wrapped-text`、`checkbox-states`、`mixed-sparkline-progress`、`switch-button`、`inline-image`、`link-merged-auto-height`、`style-underline`、`checkbox-header-options`、`checkbox-over-thousand-rows` | 文本、复选框、火花线、进度条、开关、按钮、内联图片、合并链接及禁用跳转、下划线 | -| 布局与主题 | `auto-width-height`、`adaptive-width`、`layout-container-fit-height`、`layout-container-fit-both`、`frozen-short-content-connected`、`theme-dark-icons`、`theme-update-theme`、`layout-min-max-adaptive-width`、`pivot-max-frozen-width`、`frozen-shadow-start`、`frozen-shadow-middle`、`frozen-shadow-end`、`scrollbar-ignore-frozen`、`layout-auto-fill-width-resize-container` | 自适应尺寸、冻结边界、深色图标、运行时主题更新、自适应列宽上下限、透视冻结宽度上限 | -| 透视表 | `pivot-analysis-two-level`、`pivot-virtual-column-total`、`pivot-calculated-field-hidden-dependencies`、`pivot-custom-merge-subtotal`、`pivot-indicator-sort-subtotal`、`pivot-custom-sort-click-colors`、`pivot-aggregation-rules`、`pivot-tree-zero-expand`、`pivot-update-sort-state-click`、`pivot-initial-column-sort-state`、`pivot-custom-total-data-tree`、`pivot-corner-empty-matrix`、`pivot-empty-string-dimension`、`pivot-resize-indicator-row`、`pivot-corner-sort-one-dimension`、`pivot-corner-sort-two-dimensions`、`pivot-update-sort-rules-after-click`、`pivot-indicator-hide-frozen`、`pivot-color-legend-order`、`pivot-chart-spec-mark-line` | 维度层级、虚拟节点、隐藏依赖指标、SUM/COUNT/AVG 聚合、指标路径排序、自定义比较器与双指标着色、小计、初始列树排序状态与点击后更新排序状态、显式汇总记录、空维度矩阵、空字符串维度、指标行拖动调整行高、单级与两级角头初始排序图标、按维度隐藏指标、右列与底行冻结、顶部图例布局、单元格图表标记线 | -| 透视图 | `pivot-chart-box-plot`、`pivot-chart-box-plot-horizontal`、`pivot-chart-histogram-overlap`、`pivot-chart-heatmap-two-indicators`、`pivot-chart-scatter-axes`、`pivot-chart-mark-line`、`pivot-chart-combination-forecast`、`pivot-chart-sunburst-hierarchy`、`pivot-chart-histogram-color`、`pivot-chart-bar-line-right-axis`、`pivot-chart-pie-multi-select`、`pivot-chart-circle-packing-hierarchy`、`pivot-chart-crosshair-linkage-hover`、`pivot-chart-brush-multiple-selection`、`pivot-chart-area-axis-sort`、`pivot-chart-rose-indicator-title` | 箱线图、直方图、热力图、散点图、组合预测图、旭日图、标记线与颜色映射、左右双轴柱线图、饼图图元多选、圆形打包图、跨图表悬停准线与提示、面积图、玫瑰图与指标标题 | -| Gantt | `gantt-taskbar-relative-rect`、`gantt-baseline-overlap`、`gantt-project-range-set-records`、`gantt-empty-mark-line`、`gantt-baseline-padding-static`、`gantt-baseline-padding-function`、`gantt-locate-offscreen-task`、`gantt-move-task-bar`、`gantt-tree-move-resize`、`gantt-resize-task-list-header` | 任务条拖动、基线间距、记录更新后的时间边界、空任务标记线、离屏定位、树形子任务条移动与拉伸、任务列表列头拖动后双层时间轴布局 | -| Sheet | `sheet-add-columns`、`sheet-insert-columns-before-second`、`sheet-insert-columns-before-third`、`sheet-insert-rows-at-start`、`sheet-insert-rows-after-first`、`sheet-formula-edit`、`sheet-copy-paste`、`sheet-update-option`、`sheet-cross-tab-formula`、`sheet-formula-auto-fill-copy` | 列与行的插入位置边界、跨表公式、公式结果格的复制填充、事件剪贴板、配置更新 | -| 插件 | `plugin-filter-hide-reorder`、`plugin-master-detail-auto-height`、`plugin-fill-handle-hit-area`、`plugin-context-menu-click`、`header-grid-tree-filter-expand`、`plugin-auto-fill-grid-tree-origin-value`、`plugin-excel-delete-range` | 筛选与列移动、主从表、填充柄命中范围、上下文菜单、Delete 清空可编辑选区 | -| 交互与组件 | `select-cross`、`keyboard-copy-paste-event`、`sort-multiple-header-click`、`edit-complete-input`、`component-legend-resize`、`menu-dropdown-highlight`、`hover-tooltip`、`drag-column-header`、`select-disable-callback`、`blank-area-deselect`、`disabled-arrow-navigation`、`drag-row-series-select`、`drag-row-series-order`、`keyboard-cut-paste-event`、`resize-row-height`、`hover-cross`、`hover-row`、`hover-column`、`hover-single`、`select-drag-outside`、`select-header-cell`、`select-column-disabled`、`select-global-disabled`、`select-header-disabled-drag`、`select-highlight-row`、`select-highlight-column`、`select-highlight-cross-theme`、`select-highlight-cross-header-cell`、`select-highlight-cross-transpose`、`disable-hover-columns`、`select-highlight-in-range`、`select-header-scroll-top`、`double-click-auto-column-width`、`double-click-auto-width-height` | 列拖动、回调禁选、选择、复制粘贴、复合排序、编辑、图例缩窄、下拉菜单、提示、空白区清选、禁选列键盘导航、行序号拖选与重排、剪切粘贴、列表行高拖动、悬停四模式、列级与全局禁选 | -| 数据与 API | `aggregation-pagination`、`filter-api`、`records-add-sorted`、`records-delete-sorted`、`transpose-update-option-off`、`api-update-columns`、`api-change-cell-values`、`records-add-pagination`、`promise-custom-merge`、`promise-keep-data`、`frozen-empty-records-header`、`api-update-columns-on-mouseleave`、`api-update-columns-after-selection` | 聚合、筛选、分页插入、异步数据自定义合并、排序状态下增删记录、转置更新、列更新、二维批量改单元格、异步数据源配置更新时保留数据 | -| 其他结构 | `tree-list-merge-expand`、`tree-checkbox-set-state`、`transpose-theme-header`、`progress-custom-layout`、`group-one-column`、`tree-checkbox-add-record`、`tree-checkbox-delete-record`、`tree-lazy-record-children`、`tree-pagination-double-click`、`tree-filter-clear-lazy`、`group-add-delete-records` | 树展开、树复选状态、树节点增删与懒加载、分页双击、转置、自定义布局、两级分组内路径增删、树形列表过滤与懒加载 | +| 用例目录 | 已有代表场景 | +| --- | --- | +| `table`、`header`、`cells` | 列表与多级表头、合并单元格、行序号、文本/复选框/开关/按钮/图片/链接等单元格类型 | +| `pivot`、`pivot-chart` | 维度、聚合与汇总、指标隐藏、排序、冻结、图例,以及面积图、玫瑰图、箱线图、热力图、散点图、旭日图等图表和交互 | +| `gantt`、`sheet`、`plugins` | 任务条与基线、公式及行列插入、筛选/填充柄/主从表/Excel 键盘插件 | +| `layout`、`frozen`、`scroll`、`theme`、`style`、`language`、`empty` | 自动尺寸、冻结区与阴影、滚动、主题和样式、多语言及空状态 | +| `interaction`、`keyboard`、`edit`、`sort`、`menu` | 悬停与选择、拖动和尺寸调整、复制粘贴、编辑、排序及菜单 | +| `analysis`、`records`、`tree`、`group`、`transpose`、`api`、`data`、`components`、`custom` | 过滤与聚合、记录更新、树/分组、转置、异步数据、API 更新和自定义布局 | -Sheet 复制填充当前只断言邻格显示值,不代表公式引用平移。仍未建立独立的视频与远程资源、透视树扩展标题路径与懒加载、大规模多级分组动态更新、大数据性能视觉回归。已发现的官方基线行为问题保留在下述去向台账和仓库外私有复现记录,不把失败场景登记为通过用例。旧 BugServer 目录存在大量重复与混杂项;全量来源先在仓库外筛查,再按真实功能和动作选择可公开的代表用例。新增功能或缺陷修复优先补充对应触发条件,不以数量填充用例。 +## 当前边界 -## BugServer 未选候选去向(2026-09-24) +- Sheet 公式复制填充目前断言邻格显示值,未验证公式引用随位置平移。 +- 远程媒体资源、大规模数据的性能,以及透视树扩展标题路径与懒加载、多级分组的大规模动态更新,不属于当前本地视觉用例的已验证范围。 +- 官方基线无法正常执行的来源不登记为通过用例。新增功能或修复缺陷时,优先增加对应触发条件和结果断言;不要以用例数量或配置关键词推断覆盖率。 -已审阅的 528 条候选已按来源摘要、配置及 API 信号、录制动作逐条登记在 [去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json)。状态为 `migrated` 的 67 条均指向实际运行的本地用例及断言;`deferred_*` 只表示尚未证明本地覆盖,不应据相似配置名或 AST 结构推断等价。 - -| 去向 | 数量 | 含义 | -| --- | ---: | --- | -| 已迁入本地用例 | 67 | 58 个新模块,以匿名数据重建配置及动作 | -| 隐私风险排除 | 19 | 发现业务化字段或数值,原始内容没有进入仓库 | -| 官方基线待查 | 1 | 初始排序状态存在,但预期记录顺序未改变 | -| 外部资源待替换 | 31 | 需要确定性的本地资源后才能验证 | -| 大型源码待缩减 | 68 | 需要缩成匿名且仍保留关键边界的数据 | -| 交互未证明覆盖 | 136 | 录制动作缺少对应的本地动作与断言 | -| 静态配置未证明覆盖 | 206 | 配置或数据变体缺少对应的本地断言 | - -三条含人名与编号的 `changeCellValues` 来源按用户决定列为隐私风险排除;另有包含订单和客户标识的主从表来源、包含业务流程信息的 Gantt 来源排除。独立的 `api-change-cell-values` 与 `gantt-resize-task-list-header` 使用匿名固定数据,不关联被排除来源 ID。 - -新补充的冻结与配置场景:overflow 阴影滚动三边界、主滚动条包含冻结列宽度、311 列下清空记录后保留表头,以及复选框表头变体。单例与相关目录均通过官方基线比较。 - -已补齐选择高亮的 row、column、带主题 cross、表头单格和转置变体,并加入行序号拖动两次后的记录重排;逐例保留真实来源 ID,验证动作顺序与最终状态。 - -新补充的交互场景:四种悬停模式、连续选择与表外点击、表头单格选择、列级和全局禁选、禁选表头下仍可拖动换列。当前全量 204/204 与官方基线通过,独立匿名 Gantt 列头拖动单例通过。 - -本轮新增可验证场景:Sheet 在第二列和第三列前插列,以及首条和第二条记录前插行,已用实际数值位置断言;列头标题层、初始复合排序、自动列宽上限、记录驱动行高、固定画布与自动画布尺寸、左右冻结区拖动及滚动、折叠树复选状态和零高度行、角头剩余三种排列、指标组行高拖动、转置表仅按表体计算列宽。待查初始排序 case ID:`66c54ebdc3ab4200c6b4fdf6`。此前五条基线问题继续保留:`6731de62013a5500b2fe995f`、`69646241e4654d005ebc40ed`、`655c9445ba621bd56533efcb`、`6855015beb13a600a741dd62`、`69d4cbe3547bee005d6c8482`。 - -本轮新增列级悬停禁用、跨表头选择、滚动后表头选择、鼠标事件回调更新列、拖动及双击列宽、插件填充柄复制、千行复选框、透视排序规则更新和透视图框选。另将 7 条含订单/客户标识或人员邮箱字段的来源标为隐私排除。 - -最后一轮定向补充 7 个模块、8 条真实来源 ID:合并链接、透视指标隐藏与冻结、连续色彩图例、PivotTable 图表标记线、面积图、玫瑰图、Excel 键盘删除选区。按“绝大多数配置和模块有代表用例”的标准,迁移已基本完成;台账中的剩余候选仍可用于未来针对具体缺陷选例,不应按未迁条数推断覆盖率。业务风险排除项不提供源码或字段原文;未来重新筛查应重新从 BugServer 获取来源并核对 `sourceDigest`。 +运行方式、报告和失败含义见[视觉测试说明](../README.md),新增用例与真实 BugServer 来源 ID 规则见[用例指南](./README.md)。 diff --git a/packages/vtable/__tests__/visual/cases/README.md b/packages/vtable/__tests__/visual/cases/README.md index 78f42719ba..1b2d86d10f 100644 --- a/packages/vtable/__tests__/visual/cases/README.md +++ b/packages/vtable/__tests__/visual/cases/README.md @@ -14,8 +14,8 @@ 新增用例先查找已有近邻,优先在一个明确场景中补强必要条件。模块默认导出 `mount(container)`、`verify(page)` 和可选 `exercise(page)`;`mount` 返回待测实例。输入必须固定、公开、无外网依赖。`exercise` 需要执行真实动作,`verify` 需要检查目标状态;截图负责外观,不能替代语义断言。模块和核心方法写中文目的注释。登记唯一短 ID、目的、文件及所需 `bundles`;未登记模块不会执行。 -迁移模块头部使用 `BugServer case IDs: <真实ID>`;合并时列出全部真实来源 ID,改写时仍保留原 ID。该 ID 仅用于追溯,不表示与线上内容实时同步。开发者新建的本地用例不填空值或占位 ID,待后续反向同步成功后再写入服务返回的真实 ID。不得复制业务原文、内部地址、凭证、原始数据或截图到公开仓库;来源不明时先放在私有复核目录。 +只有从 BugServer 现有 case 迁移的模块才在头部写 `BugServer case IDs: <真实ID>`;合并时列出全部真实来源 ID,改写时仍保留原 ID。开发者或编码 Agent 独立新增的本地用例完全省略这一行,不填空值、占位或虚构 ID;未来同步成功后才补写服务返回的真实 ID。该 ID 只用于追溯,不表示与线上内容实时同步。 -BugServer 未提供 `interactions` 字段时,仅表示没有附加录制动作。仍须检查源码中的事件、定时器、异步调用、构建后的 API 更新及资源。迁移时保留目标配置、数据边界、动作顺序和最终状态;只改写无关宿主与业务内容。本目录只保存脱敏的 [候选去向台账](./BUGSERVER_CANDIDATE_TRIAGE.json);原始 BugServer 来源、完整筛选台账和待审记录保存在仓库外私有目录。 +从 BugServer 迁移来源时,缺少 `interactions` 字段仅表示没有附加录制动作;仍须检查源码中的事件、定时器、异步调用、后续 API 更新及资源。保留目标配置、数据边界、动作顺序和最终状态。不得复制业务原文、内部地址、凭证、原始数据或截图到公开仓库;来源不明时先在仓库外私有目录复核。 新增或修改后先运行单例 `--self-compare --case `,再运行对应目录;提交前运行默认全量比较。若用例在官方基线不支持,报告为执行错误,应如实说明,不能把自比较当作双侧通过。