test(widgets): add TextInput dirty state tests#736
Conversation
📝 WalkthroughWalkthroughA new Vitest test suite for TextInput verifies that the ChangesTextInput dirty-state verification
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
packages/widgets/src/input/TextInput.test.ts (3)
14-45: ⚡ Quick winConsider testing that no-op operations don't mark dirty.
The current tests verify that successful mutations mark the widget dirty. For more complete coverage, consider adding tests that verify no-op operations (where guards prevent mutation) don't unnecessarily mark dirty:
insertChar()when already atmaxLengthdeleteBack()when cursor is at position 0deleteForward()when cursor is at end of value📋 Example test for no-op edge cases
it('does not mark dirty when deleteBack is no-op', () => { const input = new TextInput(); input.value = 'abc'; input.moveCursorHome(); // cursor at position 0 input.clearDirty(); input.deleteBack(); // no-op expect(input.isDirty).toBe(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 `@packages/widgets/src/input/TextInput.test.ts` around lines 14 - 45, Add tests that assert no-op operations do not mark the widget dirty: for TextInput, add cases where insertChar() is called when value length is already at maxLength, deleteBack() is called when cursor is at position 0 (use moveCursorHome() to position), and deleteForward() is called when cursor is at end (use moveCursorEnd()); in each test call clearDirty() before invoking the no-op action and assert input.isDirty is false afterwards. Use the existing test patterns around TextInput, clearDirty, isDirty, insertChar, deleteBack, deleteForward, moveCursorHome, moveCursorEnd, and maxLength to locate where to add these assertions.
58-78: 💤 Low valueConsider splitting cursor movement tests into separate cases.
All four cursor movement methods are tested in a single test case. Splitting them into individual test cases would improve debuggability and make it clearer which specific method fails if a test breaks.
🔧 Optional refactor to separate test cases
- it('marks dirty after cursor movement', () => { + it('marks dirty after moveCursorLeft()', () => { const input = new TextInput(); - input.value = 'abc'; input.clearDirty(); input.moveCursorLeft(); expect(input.isDirty).toBe(true); + }); + it('marks dirty after moveCursorRight()', () => { + const input = new TextInput(); + input.value = 'abc'; + input.moveCursorHome(); + input.clearDirty(); input.moveCursorRight(); expect(input.isDirty).toBe(true); + }); + it('marks dirty after moveCursorHome()', () => { + const input = new TextInput(); + input.value = 'abc'; + input.clearDirty(); input.moveCursorHome(); expect(input.isDirty).toBe(true); + }); + it('marks dirty after moveCursorEnd()', () => { + const input = new TextInput(); + input.value = 'abc'; + input.moveCursorHome(); + input.clearDirty(); input.moveCursorEnd(); expect(input.isDirty).toBe(true); });🤖 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 `@packages/widgets/src/input/TextInput.test.ts` around lines 58 - 78, Split the single "marks dirty after cursor movement" test into four focused tests: one each for moveCursorLeft, moveCursorRight, moveCursorHome, and moveCursorEnd. For each new test, instantiate TextInput, set input.value = 'abc', call input.clearDirty(), invoke the specific cursor method (moveCursorLeft / moveCursorRight / moveCursorHome / moveCursorEnd), and assert expect(input.isDirty).toBe(true); keep helper calls (clearDirty, value setup) consistent across tests to keep them independent and debuggable.
1-79: TextInput.test.ts: No need forScreenwhen only asserting dirty-state; addScreenrendering tests only for output assertions
- Current tests validate
isDirty/markDirtybehavior withoutnew Screen, which matches existing widget unit tests (e.g.,packages/widgets/src/data/markDirty.test.ts,packages/widgets/src/input/CommandPalette.test.ts,packages/widgets/src/layout/Stack.test.ts).- Add a separate test that constructs a real
Screen, callsupdateRect(), andrender()if you need assertions about rendered characters/cursor positioning.🤖 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 `@packages/widgets/src/input/TextInput.test.ts` around lines 1 - 79, The current tests in TextInput.test.ts correctly assert isDirty/markDirty behavior without creating a Screen; keep those unit tests as-is, and add a new test file (or new test case) that constructs a real Screen, attaches the TextInput, calls updateRect() and render() on the Screen, then asserts rendered output/cursor positions—use Screen, Screen.updateRect(), Screen.render(), and TextInput methods (value, moveCursor*, insertChar, deleteBack, deleteForward) for the rendering-specific assertions so dirty-state tests remain isolated from rendering concerns.
🤖 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.
Nitpick comments:
In `@packages/widgets/src/input/TextInput.test.ts`:
- Around line 14-45: Add tests that assert no-op operations do not mark the
widget dirty: for TextInput, add cases where insertChar() is called when value
length is already at maxLength, deleteBack() is called when cursor is at
position 0 (use moveCursorHome() to position), and deleteForward() is called
when cursor is at end (use moveCursorEnd()); in each test call clearDirty()
before invoking the no-op action and assert input.isDirty is false afterwards.
Use the existing test patterns around TextInput, clearDirty, isDirty,
insertChar, deleteBack, deleteForward, moveCursorHome, moveCursorEnd, and
maxLength to locate where to add these assertions.
- Around line 58-78: Split the single "marks dirty after cursor movement" test
into four focused tests: one each for moveCursorLeft, moveCursorRight,
moveCursorHome, and moveCursorEnd. For each new test, instantiate TextInput, set
input.value = 'abc', call input.clearDirty(), invoke the specific cursor method
(moveCursorLeft / moveCursorRight / moveCursorHome / moveCursorEnd), and assert
expect(input.isDirty).toBe(true); keep helper calls (clearDirty, value setup)
consistent across tests to keep them independent and debuggable.
- Around line 1-79: The current tests in TextInput.test.ts correctly assert
isDirty/markDirty behavior without creating a Screen; keep those unit tests
as-is, and add a new test file (or new test case) that constructs a real Screen,
attaches the TextInput, calls updateRect() and render() on the Screen, then
asserts rendered output/cursor positions—use Screen, Screen.updateRect(),
Screen.render(), and TextInput methods (value, moveCursor*, insertChar,
deleteBack, deleteForward) for the rendering-specific assertions so dirty-state
tests remain isolated from rendering concerns.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dfefbe6d-6384-4103-a841-33bc9f06fe89
📒 Files selected for processing (1)
packages/widgets/src/input/TextInput.test.ts
|
Thanks for the review. I checked the failing CI job and the failure originates from Locally, the added TextInput tests pass successfully, and the failure appears to be caused by the current Meter implementation/test setup on the base branch. |
Description
Adds regression tests for TextInput dirty-state propagation.
The new test suite verifies that all state-mutating methods correctly mark the widget as dirty after updating internal state. This helps prevent future regressions of the TextInput rendering bug fixed in #675.
Related Issue
Closes #686
Which package(s)?
@termuijs/widgets
Type of Change
type:bug)type:feature)type:docs)type:testing)type:refactor)type:design)type:accessibility)type:performance)type:devops)type:security)Checklist
needs-starcheck blocks your merge otherwise.bun vitest runbun run buildbun run typecheckCONTRIBUTING.md.type: short description.markDirty()(if your change affects rendering).anytypes without an inline comment explaining why.GSSoC 2026 Participation
https://gssoc.girlscript.org/profile/a80c7e63-fb5a-4d58-aec9-115f9a2798b7Screenshots / Recordings (UI changes)
N/A
Notes for the Reviewer
This PR adds regression tests for TextInput dirty-state propagation.
The test suite covers:
These tests provide regression coverage for the TextInput dirty-state behavior introduced in the fix for issue #675 and help prevent similar rendering issues from being reintroduced in future changes.
Validation completed:
bun vitest run packages/widgets/src/input/TextInput.test.ts✅bun run build✅Note: repository-wide
bun run typecheckcurrently reports failures in the recently addedexamples/markdown-editorpackage that are unrelated to this PR.Summary by CodeRabbit