test(ui): scale test casees and enforce coverage#272
Conversation
Introduce a three-layer UI test harness with shared fixtures: - unit (Vitest node) fills chart option/dispatch and embed/init gaps - integration (happy-dom + VTU) covers LoadError, ChartCard, SettingsPanel - Playwright e2e smokes with a static contract fixture Delete the fake SettingsPanel registry suite, centralize test-utils, and document layers in ui/TESTING.md and AGENTS.md.
Add @vitest/coverage-v8 and gate statements/branches/functions/lines at 100% for src + embed-build (excluding pure re-export barrels). Expand unit and integration suites across composables, chart options, lib/builders, workers, feature components, settings controls, ui primitives, and embed-build plugins. Wire pnpm test:coverage and task test:ui:coverage.
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe PR adds layered UI testing infrastructure, Playwright E2E coverage, extensive Vue and chart integration tests, shared fixtures, worker test utilities, and edge-case validation across charting, data, routing, statistics, and embedding behavior. ChangesUI testing system
Estimated code review effort: 5 (Critical) | ~120 minutes Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
Align fixtures and mocks with StatConfig/DataPoint/Render3D/Dataset types so CI lint (vue-tsc) passes without weakening coverage gates.
Keep nullish cellTotals/type branches exercised via typed casts so coverage thresholds and vue-tsc both stay green.
There was a problem hiding this comment.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ui/src/composables/useUrlRouter.ts (1)
146-157: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
once: truespends the deferred group watcher even when the first length change can't satisfyg.The watcher fires on the first change to
resultGroups.value.lengthand is then disposed, whether or notapplyIndexParamaccepted the index. If groups populate in more than one step (or the first batch is shorter thang), the deep-linked group is silently dropped and never reapplied — your own test atui/src/composables/useUrlRouter.test.tsLines 518-532 encodes that drop. Fallback to group 0 keeps this non-critical, but a self-disposing watch would be more faithful to the intent.🛡️ Proposed fix
} else if (gParam !== undefined) { - // once:true fires on the first length change; applyIndexParam validates the index. - watch( - () => resultGroups.value.length, - (len) => applyIndexParam(gParam, len, selectGroup), - { once: true } - ) + // Keep watching until the index is actually applicable — groups may + // populate in more than one step. + const stop = watch( + () => resultGroups.value.length, + (len) => { + if (len === 0) return + applyIndexParam(gParam, len, selectGroup) + if (isValidIndex(parseInt(gParam, 10), len)) stop() + } + ) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useUrlRouter.ts` around lines 146 - 157, Update the deferred watcher in the group-ID handling block of useUrlRouter so it remains active until resultGroups.value.length is sufficient for applyIndexParam to accept gParam, then stop the watcher after successful application. Preserve the immediate path for already-populated groups and avoid dropping the deep-linked group when population occurs in multiple batches.
🧹 Nitpick comments (48)
ui/e2e/load-error-retry.spec.ts (1)
1-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the documented
describe/itconvention for all Playwright cases.
ui/e2e/load-error-retry.spec.ts#L1-L4: declare the retry case withit.ui/e2e/settings-url.spec.ts#L1-L4: declare the settings case withit.ui/e2e/stats-csv.spec.ts#L1-L4: declare the CSV case withit.As per coding guidelines,
ui/e2e/**/*.spec.tscases useitwithindescribe.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/e2e/load-error-retry.spec.ts` around lines 1 - 4, Use the documented describe/it convention by changing the test declaration to it in ui/e2e/load-error-retry.spec.ts lines 1-4, ui/e2e/settings-url.spec.ts lines 1-4, and ui/e2e/stats-csv.spec.ts lines 1-4; leave the surrounding describe blocks and test behavior unchanged.Source: Coding guidelines
ui/e2e/deep-link.spec.ts (1)
3-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
itfor Playwright cases consistently.
ui/e2e/deep-link.spec.ts#L3-L4: aliastestasitand useit(...)for the case.ui/e2e/embed-load.spec.ts#L3-L4: aliastestasitand useit(...)for the case.As per coding guidelines,
ui/e2e/**/*.spec.tsmust group behavior withdescribe, usingitfor cases.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/e2e/deep-link.spec.ts` around lines 3 - 4, Use the aliased `it` identifier consistently for Playwright cases: in ui/e2e/deep-link.spec.ts lines 3-4, alias the imported `test` as `it` and replace the case declaration with `it(...)`; apply the same alias and case update in ui/e2e/embed-load.spec.ts lines 3-4.Source: Coding guidelines
ui/src/components/ChartCard.integration.test.ts (3)
173-177: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicated ref resets in
beforeEach.
chartTypeRef.value = 'bar'andthreeDRef.value = falseare each assigned twice.♻️ Cleanup
holder.chartType = 'bar' chartTypeRef.value = 'bar' - chartTypeRef.value = 'bar' holder.threeD = false threeDRef.value = false - threeDRef.value = false🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/ChartCard.integration.test.ts` around lines 173 - 177, Remove the duplicate assignments in the beforeEach setup, keeping one chartTypeRef.value reset to 'bar' and one threeDRef.value reset to false while preserving the existing holder.threeD initialization.
333-342: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest depends on state captured by earlier mounts.
holder.loadingComp/errorCompare only populated whendefineAsyncComponentruns, so this case silently relies on module import/earlier tests rather than its own arrangement. Also, theif (typeof ...)guards mean the assertions can be skipped entirely without failing. Consider mounting within the test and asserting unconditionally.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/ChartCard.integration.test.ts` around lines 333 - 342, Update the “invokes async loading and error placeholders” test to mount the component or otherwise trigger its async setup within the test before reading holder.loadingComp and holder.errorComp. Remove the typeof guards and assert both placeholders unconditionally, including invoking them when appropriate so the test cannot pass without exercising its own arrangement.
285-298: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThese two tests only assert the stub exists, so they can't fail for the right reason.
pass-through option updatesandfreezes buffer while loadingare named around option propagation/freezing, but neither inspects the option actually bound to the chart. Assert the stub'soptionprop (e.g.w.findComponent({ name: /ChartStub/ })...props('option')) so the buffered-vs-live behavior is verified.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/ChartCard.integration.test.ts` around lines 285 - 298, The tests “pass-through option updates when not loading” and “freezes buffer while loading true” only verify rendering, not option propagation. Update both tests to inspect the chart stub’s bound option prop via the ChartStub component: assert the new option is exposed when not loading, and assert the previously buffered option remains exposed while loading.ui/src/components/charts.integration.test.ts (1)
80-82: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
expect(name).toBeTruthy()is a no-op.
nameis the literal fromit.each; the assertion exists only to consume the parameter. Drop it (or usenamein the assertion message instead).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/charts.integration.test.ts` around lines 80 - 82, Remove the redundant expect(name).toBeTruthy() assertion from the it.each test, since name is always a literal parameter; leave the meaningful useMock assertion unchanged.ui/src/composables/charts/shared/chartConfig.test.ts (3)
329-341: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueInconsistent import style within the same file.
Some new suites resolve helpers via
await import('./chartConfig')while adjacent ones (e.g.createValueAxisConfig,createTooltipConfig,renderDonutSvg) use the existing top-level static import. Unless the lazy import is needed for mock ordering, prefer the static imports already at the top of the file.Also applies to: 344-349
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/chartConfig.test.ts` around lines 329 - 341, Update the createHorizontalDataZoomConfig tests to use the file’s existing top-level static imports instead of await import('./chartConfig'); apply the same change to the related tests at lines 344-349, preserving their current assertions and behavior.
472-480: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
typeof html === 'string'asserts nothing.
tooltipSpreadRowsalways returns a string, and the non-finite path is properly covered by the dedicated suite at Lines 548-566. Assert the concrete output for[0, 0, 0]or drop this case.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/chartConfig.test.ts` around lines 472 - 480, Update the non-finite stats test for tooltipSpreadRows to assert the concrete expected output for [0, 0, 0], matching the behavior covered by the dedicated non-finite suite, or remove this redundant case; do not retain the vacuous typeof html assertion.
429-439: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueComments reference an absolute source line and describe unreachable branches.
"dead branch at 746" will rot on the next edit to
chartConfig.ts, and therenderDonutSvg total guardtitle claims a non-positive-total branch while the assertion really covers the<2 positivesguard. Rename the case (e.g. "returns empty when fewer than two positive slices") and refer to the symbol rather than a line number.Also applies to: 496-500
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/chartConfig.test.ts` around lines 429 - 439, Update the affected renderDonutSvg tests to remove absolute source-line references and rename the case to describe the behavior actually asserted: returning an empty string when fewer than two positive slices remain. Reference the renderDonutSvg symbol and its positive-slice guard rather than calling the branch unreachable or naming a non-positive-total condition.ui/src/components/StatsPanel.integration.test.ts (2)
248-251: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStubbing the whole
URLglobal dropsnew URL(...)for the duration of these tests.Only the two static methods are needed; replacing the constructor makes any incidental
new URL()in the component or its dependencies throw. Prefer spying on the real object.♻️ Narrower stub
- vi.stubGlobal('URL', { - createObjectURL, - revokeObjectURL, - }) + vi.spyOn(URL, 'createObjectURL').mockImplementation(createObjectURL) + vi.spyOn(URL, 'revokeObjectURL').mockImplementation(revokeObjectURL)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/StatsPanel.integration.test.ts` around lines 248 - 251, Update the URL setup in the StatsPanel integration tests to preserve the real URL constructor while mocking only createObjectURL and revokeObjectURL. Replace the whole-global vi.stubGlobal call with spies on the existing URL static methods, and retain the current mock implementations and cleanup behavior.
750-831: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftCoverage-driven cases with no (or conditional) assertions.
setupState branch hammerpatchesArray.prototype.sortglobally and mutates$.setupStatedirectly without asserting any outcome; the axis-selector cases guard assertions behindif (selectors[1])andtoBeGreaterThanOrEqual(before), which pass regardless of behavior. These lift coverage numbers without protecting behavior and will break on any internal rename. Consider driving these branches through props/DOM and asserting concrete rendered output.Also applies to: 372-376, 471-484
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/StatsPanel.integration.test.ts` around lines 750 - 831, The tests around setupState branch coverage, including the `setupState branch hammer` case and the referenced axis-selector cases, need behavioral assertions instead of direct internal-state access. Drive sorting, correlation-axis selection, and related branches through mounted component props and DOM interactions, then assert concrete rendered output or user-visible state; remove the global `Array.prototype.sort` patch and avoid assertions that are unconditional or pass regardless of behavior.ui/src/composables/charts/shared/visualMap.test.ts (1)
34-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOne
itcovers three unrelated assertions.The title only describes the
<= 0fallback, yet the body also checks the positive max andresolve2DScatterVisualMap's default dimension. Split into separateitcases so a failure names the broken contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/visualMap.test.ts` around lines 34 - 44, Split the combined test in the maxFromScatterValues describe block into separate it cases: keep the non-positive fallback assertions together, move the positive maximum assertion into its own clearly titled case, and move the resolve2DScatterVisualMap default-dimension assertion into another case so failures identify the affected contract.ui/src/components/simple.integration.test.ts (2)
157-168: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove the shared
historyfixture intoui/src/test-utils.This
HistoryEntry[]fixture is reused byHistoryPopover, the meta badges, andDatasetHeadercases here and is the kind of data other suites will want. As per coding guidelines, "share fixtures fromui/src/test-utils".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/simple.integration.test.ts` around lines 157 - 168, Move the shared HistoryEntry[] fixture currently declared as history into ui/src/test-utils, then update the HistoryPopover, meta badge, and DatasetHeader test cases to import and reuse that fixture instead of defining it locally.Source: Coding guidelines
369-372: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer asserting on
w.html()directly.Concatenating
classes().join(' ')withhtml()obscures which surface carriesmin-h-[32rem];expect(w.html()).toContain(...)(or a class assertion on the root) is clearer.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/simple.integration.test.ts` around lines 369 - 372, Update the LoadError test using w to assert directly against w.html() for min-h-[32rem], removing the classes().join(' ') concatenation so the asserted markup surface is clear.ui/src/components/settings/controls.integration.test.ts (2)
245-247: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMissing
awaitbefore asserting the ignored index.Every other emission in this file is awaited; here the assertion runs without flushing, so it would pass even if an emission were queued. Await the emit for consistency.
♻️ Proposed change
const vm = w.findComponent({ name: 'Selector' }) - vm.vm.$emit('select', 99) + await vm.vm.$emit('select', 99) expect(vals).toEqual(['y/x'])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/settings/controls.integration.test.ts` around lines 245 - 247, Await the Selector component’s select emission in the test before asserting vals, updating the vm.vm.$emit call for the ignored index while preserving the existing expected result.
93-112: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
asyncfactory with noawait.The
SettingsToggle.vuemock factory isasyncbut never awaits (unlike theimportOriginalmocks). Dropasyncto match the other plain stubs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/settings/controls.integration.test.ts` around lines 93 - 112, Remove the unnecessary async modifier from the SettingsToggle.vue vi.mock factory. Keep the existing defineComponent stub, props, emits, and setup behavior unchanged.ui/src/components/DescriptiveColumnSelect.integration.test.ts (2)
175-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale comment contradicts the
ghostmock.The comment says the unknown-key path is "hard" to hit, but lines 91-97 mock
isDescriptiveColumnKeyprecisely to make'ghost'pass the guard while lookup fails — which line 178 exercises. Update the comment so the intent of the mock is clear.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/DescriptiveColumnSelect.integration.test.ts` around lines 175 - 178, Update the comment above the filter assertions to explain that the mocked isDescriptiveColumnKey allows the 'ghost' key past the guard while lookup fails, and that the assertion exercises this unknown-key path; remove the stale claim that the path is hard to hit.
29-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnused
exposeAPI in the Combobox stub.
setModel/setSearch/runFilterare never used; the tests drive the component viacb.vm.$emit(...)andcb.props('filterFunction'). Dropping theexposeblock keeps the stub minimal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/DescriptiveColumnSelect.integration.test.ts` around lines 29 - 40, Remove the unused expose API from the Combobox stub’s setup function, including setModel, setSearch, and runFilter; retain the existing props, emit, and slots handling used by the tests.ui/src/components/Selector.integration.test.ts (2)
38-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnused stub buttons.
emit-value,emit-open-false, andemit-searchare never clicked; every test emits throughcb.vm.$emit(...). Consider trimming the stub.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/Selector.integration.test.ts` around lines 38 - 65, Remove the unused stub buttons with test IDs emit-value, emit-open-false, and emit-search from the rendered selector stub; the tests already trigger these events through cb.vm.$emit(...), so preserve the existing test behavior while trimming only these unreachable controls.
184-187: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSeveral new cases assert nothing falsifiable. These sites appear written to reach uncovered branches for the new 100% thresholds, but their assertions pass regardless of behavior, so the coverage they add is not protective.
ui/src/components/Selector.integration.test.ts#L184-L187: replace the monotoniccount >= beforecheck with the exact expectedselectemission count after close.ui/src/components/SettingsPanel.integration.test.ts#L279-L285: replaceexpect(w.exists()).toBe(true)with an assertion on the swap/3D control state produced by the empty arrangement map.ui/src/components/simple.integration.test.ts#L443-L453: assertpop.exists()and emitupdate:openunconditionally instead of guarding withif.ui/src/components/Selector.integration.test.ts#L335-L353: assert the rendered trigger label and absence ofselect/selectValueemissions for the missing-activeId/activeValuebranch.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/Selector.integration.test.ts` around lines 184 - 187, Strengthen the listed tests with behavior-specific assertions: in ui/src/components/Selector.integration.test.ts:184-187, assert the exact select emission count after closing; in ui/src/components/SettingsPanel.integration.test.ts:279-285, assert the swap/3D control state for an empty arrangement map; in ui/src/components/simple.integration.test.ts:443-453, assert pop exists and emit update:open unconditionally; and in ui/src/components/Selector.integration.test.ts:335-353, assert the trigger label plus no select or selectValue emissions for missing activeId/activeValue.ui/src/composables/charts/shared/3d.test.ts (1)
743-760: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest name doesn't match what is set up or asserted.
aggPointsis non-empty here, so legend totals are present, and no assertion checks that anyΣtag is omitted — only'Z1'and'<svg'. Either drop the "omits Σ tags" claim (the empty-aggPointscase at lines 666-677 already covers it) or assert the color-fallback effect explicitly, e.g. that the rendered dot/donut uses the empty-string color.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/3d.test.ts` around lines 743 - 760, The test name for the case around create3DTooltipFormatter does not match its setup or assertions. Rename it to describe the non-empty aggPoints color-fallback scenario, or change the fixture to empty aggPoints and assert Σ omission; preferably keep this case focused on the mocked getNextColorFor fallback by asserting the rendered dot/donut uses an empty-string color.ui/src/components/SettingsPanel.integration.test.ts (1)
312-329: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReaching into
$.setupStatecouples the test to Vue internals.
valueFor/onUpdateare exercised here through private component internals. Prefer driving them via the stubbed control components (as the other cases do) so a Vue internal rename doesn't break the suite.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/SettingsPanel.integration.test.ts` around lines 312 - 329, Update the test case around valueFor and onUpdate to exercise these behaviors through the stubbed control components instead of accessing w.vm.$.setupState. Preserve the empty barConfigRef scenario, verify valueFor’s undefined behavior through the relevant control, and trigger the onUpdate path using the control interaction used by the neighboring tests.ui/src/composables/charts/useBarChartOptions.test.ts (2)
258-270: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse the shared
makeValueChartDatafixture.@/test-utilsalready exports amakeValueChartDatawith the samevalueTuples(seeui/src/composables/charts/shared/valueMode.test.tsline 62), so this local copy duplicates and can drift from it.As per coding guidelines, "share fixtures from
ui/src/test-utils".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useBarChartOptions.test.ts` around lines 258 - 270, Remove the local makeValueChartData fixture and import/reuse the shared makeValueChartData export from "`@/test-utils`" in the affected tests, preserving the existing test data and behavior.Source: Coding guidelines
534-549: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueWeak sort assertion. With both slots empty the comparator is a no-op, so
['A', 'B']also passes when sorting is skipped entirely. Mix one populated and one empty slot (e.g.values: [undefined as unknown as number, 5]) so ordering actually proves the?? 0fallback.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useBarChartOptions.test.ts` around lines 534 - 549, Strengthen the test around useBarChartOptions by giving the two y-axis slots different effective values: one undefined and one populated value such as 5. Keep descending sorting enabled and assert the resulting series order reflects the undefined slot being compared as 0, so the test verifies sorting and the nullish fallback rather than only the default order.ui/src/composables/charts/shared/mixedMode.test.ts (1)
64-69: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssertion doesn't verify what the title claims. Both branches only check that
axisPointerexists, so a regression swapping line/shadow pointers would pass. Assert the pointertypeinstead.♻️ Suggested tightening
- expect(line && typeof line === 'object' && 'axisPointer' in line).toBe(true) - expect(bar && typeof bar === 'object' && 'axisPointer' in bar).toBe(true) + const pointerType = (t: typeof line) => + (t as { axisPointer?: { type?: string } }).axisPointer?.type + expect(pointerType(line)).toBe('line') + expect(pointerType(bar)).toBe('shadow')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/mixedMode.test.ts` around lines 64 - 69, Strengthen the assertions in the “uses line pointer for scatter/line and shadow for bar” test by checking the axisPointer.type value returned by createMixedModeTooltip: expect the line case to use “line” and the bar case to use “shadow”, rather than only verifying axisPointer exists.ui/src/composables/charts/useHeatmapChartOptions.test.ts (3)
404-412: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueAssertion can't fail. Both the 3D and 2D heatmap paths emit
series[0].type === 'heatmap', so mockingis3Dand asserting only the type verifies nothing about the "undefined points" branch. Assert the resultingseries[0].datashape instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useHeatmapChartOptions.test.ts` around lines 404 - 412, Update the test around useHeatmapChartOptions so it verifies the undefined-points fallback through series[0].data rather than the shared series type. Keep the is3D mock and chartData setup, and assert the resulting data shape that distinguishes the undefined-points branch.
361-362: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDead
deleteimmediately followed by reassignment. Line 361 has no effect sincepointsis re-set on the next line with the same value already given togrouped3DHeatmap. Drop both lines.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useHeatmapChartOptions.test.ts` around lines 361 - 362, Remove the redundant points mutation in the affected heatmap test: delete both the delete operation and the immediately following reassignment on chartData.points. Keep the existing grouped3DHeatmap setup unchanged, since it already provides the required points value.
390-412: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winModule spies on
@/lib/utilsare restored inline instead of in a hook. In both filesspy.mockRestore()sits at the end of the test body, so a failing assertion leavesgetNextColorFor/is3Dmocked for the rest of the file and turns one failure into several.
ui/src/composables/charts/useHeatmapChartOptions.test.ts#L390-L412: addafterEach(() => vi.restoreAllMocks())to themocked color fallbacksdescribe and drop the two inlinespy.mockRestore()calls.ui/src/composables/charts/useScatter3DChartOptions.test.ts#L285-L307: add the sameafterEachto themore optional branchesdescribe and drop the inline restore.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useHeatmapChartOptions.test.ts` around lines 390 - 412, Replace inline spy restoration with describe-scoped cleanup: in ui/src/composables/charts/useHeatmapChartOptions.test.ts lines 390-412, add afterEach(() => vi.restoreAllMocks()) to the “mocked color fallbacks” describe and remove both spy.mockRestore() calls; apply the same change in ui/src/composables/charts/useScatter3DChartOptions.test.ts lines 285-307 within the “more optional branches” describe, removing its inline restore.ui/src/composables/charts/shared/valueMode.test.ts (1)
240-248: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTest name overpromises. Nothing here asserts the cross axis-pointer or the visualMap
dimension; only tooltip truthiness anditemStyle. Either asserttooltip.axisPointer.type/visualMap.dimension === 1, or rename to match what's checked.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/shared/valueMode.test.ts` around lines 240 - 248, Update the test named “uses cross pointer for scatter/line and color dim 1 without third slot” so its assertions cover the promised cross axis pointer and visualMap dimension, including tooltip.axisPointer.type and visualMap.dimension where applicable; otherwise rename the test to describe only the tooltip and itemStyle behavior it currently verifies.ui/src/composables/charts/useBar3DChartOptions.test.ts (1)
252-260: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDead
is3Dspy + assertions that don't verify the claimed nullish-points/defaults behavior. Both tests spy onis3Dfrom@/lib/utils, but the reviewed composable code never callsis3D, so the mock has no bearing on the outcome. Both also assert only generic series presence/length, which is already guaranteed by the fixed grouped render fixture regardless of whetherpointsisundefined— so the actual "nullish points treated as empty" / "without points" behavior (i.e., thepoints ?? []fallback feedingaggPoints/tooltip) is never exercised.
ui/src/composables/charts/useBar3DChartOptions.test.ts#L252-L260: drop the unusedis3Dspy and add an assertion that actually depends onpointsbeing nullish (e.g. invoke the tooltip formatter and assert it doesn't throw / returns expected text) rather than only checkingseries.length.ui/src/composables/charts/useLine3DChartOptions.test.ts#L229-L239: same fix — remove the irrelevantis3Dspy and strengthen the assertion to cover therotate/scale/pointsdefaults actually being exercised.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/charts/useBar3DChartOptions.test.ts` around lines 252 - 260, In ui/src/composables/charts/useBar3DChartOptions.test.ts:252-260, remove the unused is3D spy and assert behavior that depends on nullish points, such as invoking the tooltip formatter and verifying it returns expected text without throwing. In ui/src/composables/charts/useLine3DChartOptions.test.ts:229-239, likewise remove the is3D spy and strengthen the test to verify the rotate, scale, and points defaults are exercised rather than only checking generic series output.ui/src/composables/useChartPipeline.test.ts (1)
479-490: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAssertion doesn't cover the documented drain branch. The comments describe
pumpQueue'sdrainingearly-return, but the only assertion is that an unknown signature never becomes a slot. Consider asserting the postedcomputecalls (e.g. exactly one in-flight compute while draining) so the test fails for the right reason if the guard is removed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useChartPipeline.test.ts` around lines 479 - 490, The test case “ignores pump while already draining and drops unknown chart slots” does not verify the documented draining guard. Add an assertion on worker.postMessage calls after the recompute is queued, confirming exactly one compute request remains in flight while draining, while retaining the existing unknown-slot assertion.ui/src/workers/transform.worker.test.ts (1)
419-438: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSecond half of this test asserts nothing and never runs. With
data: []there are no signatures, sosigis always undefined and theif (sig)block is dead — the unknown-group fallback inui/src/workers/transform.worker.ts(Lines 168-172) is not covered here. Exercise it with non-empty data and a bogusgroupName, asserting a chart is still produced.♻️ Suggested rework
- // compute with empty grouped map path: re-init with empty data - send(buildInit({ data: [] })) - const sig = ready()?.signatures[0]?.signature - postSpy.mockClear() - if (sig) { - send(buildCompute({ signature: sig, groupName: 'ghost' })) - // no signatures from empty data → may be undefined - } + // unknown groupName falls back to the first group + send(buildInit()) + const sig = ready()!.signatures[0]!.signature + postSpy.mockClear() + send(buildCompute({ signature: sig, groupName: 'ghost' })) + expect(charts()).toHaveLength(1)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/workers/transform.worker.test.ts` around lines 419 - 438, Update the test case around buildInit and buildCompute so the unknown-group fallback uses non-empty data that produces a signature. Remove the empty-data guard, send buildCompute with a bogus groupName such as “ghost,” and assert that the worker produces a chart/result, thereby covering the fallback in the transform worker.ui/src/composables/useStatsWorker.test.ts (1)
149-158: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMake the id lookup robust and drop the unused
async. Line 150's test never awaits, and Line 156 assumespostMessage.mock.calls[0]is this test's request — any earlier post on the shared singleton worker (warmup or a prior test in this describe) would yield the wrong id and hang the assertion. Prefer the most recent call.♻️ Suggested tightening
- it('ignores replies for unknown ids without throwing', async () => { + it('ignores replies for unknown ids without throwing', () => { expect(() => worker.__emit({ type: 'result', id: 999_999, seriesProfiles: [] })).not.toThrow() }) it('defaults missing seriesProfiles to an empty array', async () => { const chart = makeChart('no-profiles') + worker.postMessage.mockClear() const p = computeDescriptive(chart) - const id = worker.postMessage.mock.calls[0]![0].id as number + const id = worker.postMessage.mock.calls.at(-1)![0].id as number worker.__emit({ type: 'result', id }) await expect(p).resolves.toEqual([]) })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useStatsWorker.test.ts` around lines 149 - 158, Update the tests around the unknown-id and missing-seriesProfiles cases: remove the unnecessary async modifier from the test that only checks __emit does not throw, and in the missing-seriesProfiles test obtain the request id from the most recent worker.postMessage mock call rather than index 0 so it matches computeDescriptive’s request.ui/src/workers/transform.worker.ts (1)
168-172: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueNon-null assertion on the first-group fallback is load-bearing. The invariant (a signature entry exists ⇒ at least one group) holds today, but if it ever breaks,
rowsisundefinedandbuildChartForSignaturethrows inside the worker with no reply posted — the pipeline slot stays pending forever. A?? []fallback would degrade to an empty chart instead.🛡️ Optional hardening
let rows = s.grouped.get(msg.groupName) if (rows === undefined) { // After init/arrangement the map always has at least one group. - rows = s.grouped.values().next().value! + rows = s.grouped.values().next().value ?? [] }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/workers/transform.worker.ts` around lines 168 - 172, Preserve the non-null assertion on the first-group fallback in the grouped-row lookup near buildChartForSignature. Do not replace it with a [] fallback; the existing invariant requires a group whenever a signature entry exists, and violations should remain explicit rather than producing an empty chart.ui/src/views/Dashboard.integration.test.ts (1)
34-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
holder.charts/holder.groupNames/holder.datasetInitializingare inert duplicates of the refs.Lines 65-67 snapshot those holder values once, and the
useChartPipelinemock reads only the refs — so Line 260 (and any futureholder.charts = …/holder.groupNames = …write) is a silent no-op, which is an easy trap for the next test author. Drop the holder fields and keep the refs as the single source.♻️ Proposed cleanup
- charts: [] as { key: string; data?: ChartData; pending: boolean }[], - groupNames: ['g0', 'g1'] as string[], - datasetInitializing: false, dashInit: vi.fn(),-const groupNamesRef = ref(holder.groupNames) -const chartsRef = ref(holder.charts) -const datasetInitializingRef = ref(holder.datasetInitializing) +const groupNamesRef = ref<string[]>(['g0', 'g1']) +const chartsRef = ref<{ key: string; data?: ChartData; pending: boolean }[]>([]) +const datasetInitializingRef = ref(false)- holder.datasetInitializing = false datasetInitializingRef.value = falseAlso applies to: 260-261
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/views/Dashboard.integration.test.ts` around lines 34 - 36, Remove the holder.charts, holder.groupNames, and holder.datasetInitializing fields and any reads or writes of them, including the assignments around the affected test lines. Use the existing refs directly as the single source for the mocked useChartPipeline state and related assertions.ui/src/composables/useDataPoint.test.ts (2)
508-529: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest title claims behavior it does not assert.
normalizes null settings/data on prepare and rejects catalog shells without idonly asserts the normalization half; the id rejection is covered by the separate test at Lines 531-550. Trim the title to match.♻️ Suggested rename
- it('normalizes null settings/data on prepare and rejects catalog shells without id', async () => { + it('normalizes null settings/data on prepare', async () => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useDataPoint.test.ts` around lines 508 - 529, Rename the test case beginning with “normalizes null settings/data on prepare and rejects catalog shells without id” to describe only its asserted null settings/data normalization behavior; leave the separate catalog-shell ID rejection test unchanged.
291-383: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffConsider splitting this multi-concern test.
One
itcovers arrangement, group selection, three chart-mode transitions, invalid-index selection, and the non-array guard. A failure anywhere gives one opaque red test.it.eachover the dataset/mode table plus separate cases for arrangement, groups, and the guard would localize failures.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useDataPoint.test.ts` around lines 291 - 383, Split the combined test “covers arrangement, groups, chart modes, and selection edge cases” into focused tests: separate arrangement behavior, group selection, invalid dataset selection, and the non-array datasets guard, and use an it.each table for the dataset/chart-mode transitions. Preserve all existing assertions while making each failure identify its specific behavior.ui/src/composables/useSettingsStore.test.ts (1)
84-123: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe
it.eachrows carry duplicated import/store boilerplate.Each row's
applyclosure re-imports the module and constructs the store, so the table encodes procedure rather than data. Passing the setter key and argument would collapse both rows to data and keep the arrange step in the test body.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/composables/useSettingsStore.test.ts` around lines 84 - 123, Refactor the parameterized test around the it.each table so each row supplies the setter key and argument instead of an apply closure that imports useSettingsStore and creates the store. Move the module import, store construction, and setter invocation into the test body, dynamically calling the provided setter while preserving the existing config setup and activeConfig assertion.ui/src/lib/transform.ts (1)
297-297: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicated
swapAxisLabels(...)!non-null assertion. Both sites spread a nullableAxisLabels | undefinedand silence the type with!; spreadingundefinedalready yields{}, so the assertion is pure noise.
ui/src/lib/transform.ts#L297-L297: drop the!from{ ...swapAxisLabels(identity, target, baseLabels)! }.ui/src/lib/builders/value.ts#L23-L23: drop the!from the identical expression inValueBuilder.build.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/transform.ts` at line 297, Remove the redundant non-null assertion from the spread of swapAxisLabels in ui/src/lib/transform.ts lines 297-297 and in ValueBuilder.build at ui/src/lib/builders/value.ts lines 23-23; leave the surrounding label construction unchanged.ui/src/lib/transform.test.ts (4)
841-845: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
fieldValueNameis a tautology and adds no coverage.It re-runs the same
projectValueCoords({name: undefined}, 'n', 'n')call already asserted on Line 813 and returns''by construction, soexpect(fieldValueName()).toBe('')can't fail. Either assert the projection result directly or drop the helper.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/transform.test.ts` around lines 841 - 845, Remove the tautological fieldValueName helper and its associated assertion, or replace it with a direct assertion on projectValueCoords for the undefined name case. Ensure the test independently verifies the actual projection result rather than returning a value constructed to always be ''.
883-888: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest doesn't exercise what its name claims.
skips incomplete 3D coords when a dimension maps to nameonly repeats theprojectValueCoords(..., 'xy', 'xyz')null assertion from Line 812 and never callsbuildValueModeChart. Either call the builder with an arrangement that yields incomplete coords, or remove this duplicate.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/transform.test.ts` around lines 883 - 888, The test named “skips incomplete 3D coords when a dimension maps to name” does not exercise buildValueModeChart and duplicates an existing projectValueCoords assertion. Update this test to call buildValueModeChart with an arrangement producing incomplete 3D coordinates and assert the intended skip behavior, or remove the duplicate test if that scenario cannot be constructed.
945-951: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssertion contradicts the test name.
The case is titled "skips points whose x/y are outside the index maps", but the only assertion is that
xValuescontainsMISSING— nothing is skipped, since both x values come from the samepointsarray. Rename to describe the actual behavior, or construct a canonical order that genuinely excludes an axis value (as done at Lines 1216-1232).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/transform.test.ts` around lines 945 - 951, Fix the test around the `skips points whose x/y are outside the index maps` case so its name and assertion describe the same behavior. Prefer constructing canonical index maps that exclude the stray axis value, following the pattern used around the referenced canonical-order test; otherwise rename the test to reflect that `MISSING` is included in `render.xValues`.
1131-1150: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStrip the leftover exploratory comments.
Lines 1132-1133 and 1148-1149 read as in-progress reasoning ("actually Ghost is included in sets", "wait applyCanonicalOrder filters…"). Replace with a one-line statement of the invariant each case pins.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/transform.test.ts` around lines 1131 - 1150, Remove the exploratory comments around the tests for Ghost preservation and canonical-order filtering. Replace each comment block with a single concise statement describing the invariant the test asserts, without mentioning the investigation or uncertainty; update the comments near build3DRender and cellsFor respectively.ui/src/lib/builders/builders.test.ts (2)
20-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSame
emptyChartfactory copied into two test files.ui/src/test-utils/chartFixtures.tsalready exportsemptyChartData(overrides); both files re-declare an equivalent local factory.
ui/src/lib/builders/builders.test.ts#L20-L28: replace the localemptyChartwithemptyChartDataimported from@/test-utils.ui/src/lib/utils.test.ts#L446-L454: replace the localemptyChartwith the same shared import.As per coding guidelines: "share fixtures from
ui/src/test-utils".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/builders/builders.test.ts` around lines 20 - 28, Replace the duplicated local emptyChart factories in ui/src/lib/builders/builders.test.ts#L20-L28 and ui/src/lib/utils.test.ts#L446-L454 with the shared emptyChartData import from `@/test-utils`, updating usages as needed while preserving each test’s existing override behavior.Source: Coding guidelines
500-518: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winLine 517 assertion can't fail.
After the canonical remap the tuple indices are either remapped or fall back to the original
xi, so every possible outcome satisfiesxi === 0 || xi === 1. Assert the exact expected tuples so the branch is actually pinned.💡 Suggested tightening
- expect(canon.mixedTuples?.some(([xi]) => xi === 0 || xi === 1)).toBe(true) + expect(canon.mixedTuples).toEqual([ + [0, 1], + [1, 2], + ])(adjust to the remap's real output)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/builders/builders.test.ts` around lines 500 - 518, Replace the broad some assertion in the finalizeChart test with an exact deep-equality assertion for canon.mixedTuples. Pin the remapped output produced by canonical x values A and C, including the fallback index for the missing B category, while retaining the existing xCategories assertion.ui/src/lib/utils.test.ts (1)
468-472: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
applyThememutates shared theme state with no cleanup.Any later test in this file that reads the palette now sees
#111,#222``, making results order-dependent. Wrap in a narrowly scoped hook that restores the previous theme after the case.As per coding guidelines: "Keep UI tests deterministic and beside the tested code".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/lib/utils.test.ts` around lines 468 - 472, Update the “reads active palette helpers” test around applyTheme and add a narrowly scoped cleanup hook that captures the existing theme before the test and restores it afterward. Ensure later tests observe the original palette regardless of execution order, while keeping the test beside the existing palette-helper coverage.Source: Coding guidelines
ui/src/test-utils/chartFixtures.ts (1)
163-168: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winUse
isRefhere instead of checking'value' in value.A plain object override like
visibleZ: { value: true }matches the duck-typed branch and gets treated as a ref, which breaks the config.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/test-utils/chartFixtures.ts` around lines 163 - 168, Update asRef to use Vue’s isRef predicate instead of the duck-typed `'value' in value` check, so plain object overrides are wrapped with ref while actual refs are returned unchanged.ui/src/components/ui/ui-primitives.integration.test.ts (1)
210-333: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a scoped
afterEachfor DOM-attached mounts.Both
PopoverandCombobox familyblocks mount withattachTo: document.bodyand rely on manualw.unmount()calls at the end of eachit. If an assertion throws before reachingunmount(), the attached nodes remain indocument.bodyfor subsequent tests. A narrowly-scopedafterEachper describe block would guarantee cleanup regardless of assertion outcome.As per coding guidelines,
ui/src/**/*.integration.test.tsshould use "hooks at the narrowest useful scope."♻️ Example scoped cleanup
describe('Popover', () => { + afterEach(() => { + document.body.innerHTML = '' + }) + it('mounts trigger and force-mounted content with default align', async () => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/src/components/ui/ui-primitives.integration.test.ts` around lines 210 - 333, Add scoped afterEach cleanup to the Popover and Combobox family describe blocks so DOM-attached mounts are unmounted even when assertions fail. Track each mount or otherwise clean up all attached wrappers within the corresponding describe scope, and remove the reliance on per-test manual w.unmount() calls while preserving the existing test behavior.Source: Coding guidelines
Add an e2e job to the UI workflow and gate build on it. Preserve Taskfile exit status, harden the fixture server path check, sandbox embed-build temps, restore remoteData removeRequest identity, keep deferred group URL watches alive across multi-step population, and tighten vacuous tests.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ui.yml:
- Around line 83-105: Update the e2e job in the workflow to grant only contents
read permission and configure the checkout action with persist-credentials
disabled. Apply these settings to the existing checkout/job configuration before
the install and Playwright steps, without changing the test commands.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1806d073-620a-4f86-98d4-37d19b811e3c
📒 Files selected for processing (23)
.github/workflows/ui.ymlTaskfile.ymlui/TESTING.mdui/e2e/deep-link.spec.tsui/e2e/embed-load.spec.tsui/e2e/load-error-retry.spec.tsui/e2e/serve.mjsui/e2e/settings-url.spec.tsui/e2e/stats-csv.spec.tsui/embed-build/embed-build.test.tsui/src/components/ChartCard.integration.test.tsui/src/components/Selector.integration.test.tsui/src/components/SettingsPanel.integration.test.tsui/src/components/StatsPanel.integration.test.tsui/src/components/simple.integration.test.tsui/src/components/ui/ComboboxItemIndicator.integration.test.tsui/src/composables/charts/baseChartOptions.test.tsui/src/composables/useActiveChartShape.test.tsui/src/composables/useUrlRouter.test.tsui/src/composables/useUrlRouter.tsui/src/lib/pathRoute.test.tsui/src/lib/remoteData.test.tsui/src/lib/remoteData.ts
💤 Files with no reviewable changes (1)
- ui/src/components/ChartCard.integration.test.ts
🚧 Files skipped from review as they are similar to previous changes (19)
- ui/e2e/deep-link.spec.ts
- ui/e2e/stats-csv.spec.ts
- ui/TESTING.md
- ui/e2e/settings-url.spec.ts
- ui/e2e/load-error-retry.spec.ts
- ui/e2e/embed-load.spec.ts
- ui/e2e/serve.mjs
- ui/src/components/ui/ComboboxItemIndicator.integration.test.ts
- ui/src/lib/remoteData.ts
- Taskfile.yml
- ui/src/lib/remoteData.test.ts
- ui/src/components/Selector.integration.test.ts
- ui/src/lib/pathRoute.test.ts
- ui/src/composables/useActiveChartShape.test.ts
- ui/embed-build/embed-build.test.ts
- ui/src/components/SettingsPanel.integration.test.ts
- ui/src/components/simple.integration.test.ts
- ui/src/components/StatsPanel.integration.test.ts
- ui/src/composables/useUrlRouter.test.ts
Least-privilege contents:read and persist-credentials:false for the Playwright job; install/test commands unchanged.
Replace the vacuous SwapControl-exists check with modelValue and threeD chrome assertions when arrangementMap is empty.
Run pnpm test:coverage in the UI workflow, emit lcov, and upload with flag ui. Tag CLI uploads as flag cli so both surfaces show on Codecov.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
Scale the UI test pyramid and lock Vitest coverage at 100% for included sources.
node) and integration (happy-dom+ Vue SFC mounts)ui/src/test-utils@vitest/coverage-v8with 100% statements/branches/functions/lines gatesui/TESTING.mdand wiretask test:ui/test:ui:coverage/test:ui:e2eChanges
pnpm test:unit|integration|coverage|e2eTest Result
Notes
e2e/fixtures/index.html(not the full CLI-built Vue embed).Summary by CodeRabbit