Both test files are solid. All 8 mutation experiments were caught (8/8), confirming these tests actually verify real behavior rather than being auto-generated fluff.
Tests to consider eliminating:
-
"does not render items when loading" and "does not render loading state when empty" — These test that Vue's
v-if/v-else-if/v-elsechain works correctly. This is framework behavior, not application logic. The positive tests already implicitly cover mutual exclusivity. Same for "does not render loading or empty states".That said, these are cheap to maintain and provide documentation value. Low priority to remove.
-
"shows loading indicator when isLoading is true" vs "renders default loading message" — These could be one test. The first checks
.exists(), the second checks.text(). If text is present, the element exists. Same pattern for empty state.
Suggestions:
- The
mountListhelper usesas anycast. Fine for Vue 2.7 compat. - The scoped slot test string uses Vue 2 syntax. Will need updating on Vue 3 migration.
Tests to consider eliminating: None — each test covers a distinct behavior path.
Missing coverage worth adding:
-
allSelectedfalse positive — IfselectedIdscontains IDs not initems,allSelectedcould betrueincorrectly (size match without content match). Worth a test. -
Shift-click preserves existing non-range selections — The shift-click tests start from clean state. Test: select "a", normal-click "b", shift-click "d" — does "a" remain selected?
-
pruneAfterDeletewhen no items were selected — edge case, should be a no-op.
Repeated useSidebarSelection setup could use a helper:
function setup(...ids: string[]) {
const items = ref(makeItems(...ids));
return { items, ...useSidebarSelection(items, (i) => i.id) };
}Collapses ~3 lines per test into 1. Moderate win across 18 tests.
| # | File | Mutation | Result |
|---|---|---|---|
| 1 | SidebarList.vue | role="button" -> role="link" |
CAUGHT |
| 2 | SidebarList.vue | Remove tabindex="0" |
CAUGHT |
| 3 | SidebarList.vue | "Enter" -> "Space" |
CAUGHT |
| 4 | SidebarList.vue | Remove @click handler |
CAUGHT |
| 5 | useSidebarSelection.ts | Remove lastClickedIndex.value = null in toggleSelectionMode |
CAUGHT |
| 6 | useSidebarSelection.ts | event.shiftKey -> !event.shiftKey |
CAUGHT |
| 7 | useSidebarSelection.ts | Remove empty-list guard in pruneAfterDelete | CAUGHT |
| 8 | useSidebarSelection.ts | Remove items.length > 0 guard in allSelected |
CAUGHT |
| Aspect | SidebarList | useSidebarSelection |
|---|---|---|
| Mutation kill rate | 4/4 | 4/4 |
| Redundant tests | 2-3 (low priority) | 0 |
| Missing coverage | None significant | 2 edge cases |
| Abstraction opportunity | None | setup() helper |