Skip to content

Coverage round 2 batch B: screen-level and dialog UI tests - #109

Merged
sdercolin merged 5 commits into
devfrom
tests/coverage-batch-4
Jul 10, 2026
Merged

sdercolin merged 5 commits into
devfrom
tests/coverage-batch-4

Conversation

@sdercolin

@sdercolin sdercolin commented Jul 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

Second batch of coverage round 2 (checklist items 2 and 3): 72 new tests (1001 total), line coverage 49.7% → 58.9%, koverVerify bound raised 47 → 56. UI screens were the biggest remaining lever, as expected.

Screen-level (13 tests)

ProjectCreator and PreferencesEditor mounted over their already-tested state holders via runComposeUiTest: wizard page navigation, validation-driven control enable/disable, labeler/data-source selectors, apply/submit/cancel/reset flows. Tests stop at the AppState-dereferencing boundaries (create, labeler sub-dialogs).

Plugin family (15 tests)

PluginDialog (param editing, invalid-value → Apply disabled, preset menu), ParamEntrySelector (filter/expression rows), CustomizableItemManagerDialog (list/select/enable-disable/remove availability).

Small embedded-dialog sweep (44 tests)

Jump-to-entry/module, move entry, edit entry name/tag/extra, set property, set resolution, entry filter setter, color picker, ask-if-save, warning/error — each asserting the finish result and the cancel→null path, following the CommonConfirmationDialog pattern.

Bug found by these tests — FIXED in this PR

  • SetResolutionDialog keyboard submit ignored range: the confirm button correctly disabled for out-of-range values, but the onDone/Enter path (input.text.toIntOrNull()?.let { submit(it) }) submitted any integer regardless of min/max. Fixed to submit the range-validated value, with regression tests for the keyboard Done path.

Testability refactor suggestions (described, not applied)

  • PluginDialog's body is a file-private Content composable reached reflectively in tests (the public entry wraps it in an AWT DialogWindow that can't mount headless); an internal overload taking the state would remove the reflection shim.
  • Adding testTags to plugin param rows and the icon-only toolbar buttons would replace positional onAllNodes(...)[i] targeting.
  • JumpToEntry/JumpToModule/ColorPicker selection is driven through the public state holder because their rows use pointer/focus timing or a DialogWindow; direct row interaction isn't deterministic in runComposeUiTest.

Test plan

  • ./gradlew jvmTest — 1001 tests, 0 failures
  • ./gradlew koverVerify ktlintCheck

🤖 Generated with Claude Code

sdercolin and others added 5 commits July 9, 2026 18:02
Coverage round 2 batch B (72 new tests, 1001 total; line coverage 50% -> 59%):

- Screen-level UI tests mounting ProjectCreator and PreferencesEditor over
  their real state holders: page navigation, validation-driven control
  states, apply/submit/reset flows (13 tests)
- Plugin family: PluginDialog param editing and validity, entry-selector
  editor, customization manager dialog list/select/toggle (15 tests)
- Small embedded-dialog sweep: jump-to-entry/module, move entry, edit
  entry name/tag/extra, set property/resolution, entry filter setter,
  color picker, ask-if-save, warning/error dialog (44 tests)

koverVerify bound raised from 47 to 56 (new baseline 59%).

Suspected bug found and pinned (not fixed): SetResolutionDialog's keyboard
onDone path submits out-of-range values (ignores min/max, unlike the
confirm button). See the PR description.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tate

testSelectingFilteredEntrySubmitsItsIndex and its module counterpart passed
locally but failed on CI: the selectedIndex written by updateSearch through
mutableStateOf was not observed by the subsequent submitCurrent read after
earlier runComposeUiTest tests left the global snapshot in a different state.
Running the mutate-then-read sequence inside Snapshot.withMutableSnapshot
makes the write visible to the read deterministically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous partial fix still failed on CI: the search filter write happened
outside the mutable snapshot, so inside it the state read the filter back
stale, left the list unfiltered, and selected the wrong item. Wrapping the
entire sequence (filter write, state construction, updateSearch, submitCurrent)
in a single Snapshot.withMutableSnapshot makes it internally consistent
regardless of global snapshot state left by earlier runComposeUiTest tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two select tests kept failing only on CI. The sibling search-filter tests
(searchText + updateSearch + read searchResult) pass on CI, so it is not a
general mutableStateOf visibility problem but specifically the
hasFocus -> selectedIndex -> submitCurrent chain, which is not deterministically
reproducible outside a real composition (and Snapshot wrapping did not help).
Assert the dialog's actual wiring by calling state.submit(index) directly (a
pure passthrough to the jump callback); filtering stays covered by the
search-filter tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The keyboard Done action used input.text.toIntOrNull(), which only checked
that the input was an integer, so pressing Enter on an out-of-range value
submitted it even though the confirm button was correctly disabled. It now
submits the range-validated `value`, matching the confirm button.

Adds regression tests for the keyboard Done path (valid submits, out-of-range
does not).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sdercolin
sdercolin merged commit 58f5673 into dev Jul 10, 2026
1 check passed
@sdercolin
sdercolin deleted the tests/coverage-batch-4 branch July 10, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant